Android 网络请求超时?可能与连接池和脏连接有关

在IOT开发连接Soft AP后发起网络请求时,发现一个奇怪的现象,经常有网络请求超时,一开始以为是硬件(提供Web服务)的原因,因为客户端代码看到网络请求已经出去了,但是硬件端反馈就是没收到。那问题出在哪里呢?

一、连接池与脏连接

先介绍一下基础概念。

1、为什么需要连接池

因为连接复用带来的性能收益非常大,具体对比如下:

项目 无连接池 有连接池
每次请求 建立 TCP + TLS 握手(几十~上百 ms) 直接发送请求(几 ms)
服务器负载 每次都新建 Socket、TLS 握手 复用已有连接,减少 CPU
网络流量 多次三次握手、证书传输 复用连接减少控制包
用户体验 慢、延迟高 快、流畅

我们在Android开发中一般使用的是Okhttp,Okhttp的源码中连接池的大小是5,连接的保活时间是5分钟,源码如下:

kotlin 复制代码
class ConnectionPool internal constructor(
  internal val delegate: RealConnectionPool
) {
  constructor(
    maxIdleConnections: Int,
    keepAliveDuration: Long,
    timeUnit: TimeUnit
  ) : this(RealConnectionPool(
      taskRunner = TaskRunner.INSTANCE,
      maxIdleConnections = maxIdleConnections,
      keepAliveDuration = keepAliveDuration,
      timeUnit = timeUnit
  ))
   
   //连接池默认构造
  constructor() : this(5, 5, TimeUnit.MINUTES)
...略...
}

2、什么是脏连接(stale connection)?

当客户端复用一个已经空闲的 TCP 连接时,如果 服务端已经关闭了这个连接(可能是超时、服务器主动断开、网络抖动),客户端尝试用这个连接发送请求就会失败:

kotlin 复制代码
java.io.EOFException: unexpected end of stream
java.net.SocketException: Connection reset by peer

这个连接就是所谓的 "脏连接"。因为连接池本身不知道服务端已经关闭了连接,所以当它尝试重用就会出现上面的问题。

二、遇到的问题与解决办法

当时是IOT开发,硬件侧是一个低功耗摄像头,硬件有开启一个Web服务供客户端请求,然后我发现总是有接口请求超时,我就很纳闷,硬件端抓日志说我的请求没收到???

一开始是怀疑硬件端网络请求队列的问题,因为有些页面有高并发,有些请求会不会在队列中等待时间过长就超时了? 后面放宽了超时时间,发现还是有超时现象,这就很奇怪了!!!

后面注意力才转移到脏连接上来,一开始使用了Okhtto的重试机制:

kotlin 复制代码
.retryOnConnectionFailure(true) // 保留自动重试

发现并不能解决问题,正如这个函数描述的那样:

kotlin 复制代码
/**
 * ...略...
 * Stale pooled connections. The [ConnectionPool] reuses sockets
 *   to decrease request latency, but these connections will occasionally time out.
 * ...略...
 */
fun retryOnConnectionFailure(retryOnConnectionFailure: Boolean) = apply {
  this.retryOnConnectionFailure = retryOnConnectionFailure
}

复用连接池偶尔会请求超时...

后面跟硬件工程师讨论,他说硬件端往往资源比较紧张,硬件用的这个三方网络库比较轻量,可能没有连接池这些东西或者Socket keep-alive的时间很短会及时释放。硬件工程师比较忙,也没办法继续协助我排查问题,后面查资料发现

Nginx/Tomcat 默认 Keep-Alive 超时时间可能只有 1~5 秒

这样的话使用Okhttp的连接池就没什么意义了,直接禁用了连接池解决了上面的问题:

kotlin 复制代码
.connectionPool(ConnectionPool(0, 1, TimeUnit.SECONDS))   //不复用连接

三、总结

很多看着奇奇怪怪的问题,其实很有可能是底层没有完全弄懂,要保持一定的探索欲,能解决现实问题也能让我们更加明白深层次的原理。

相关推荐
Digitally4 小时前
如何将安卓手机备份到电脑?7种方法
android
火柴就是我5 小时前
android:enableJetifier=true 再学习
android·flutter
杨筱毅5 小时前
【Android】【底层原理】深入解析SELinux模块
android·底层机制
Tom4i6 小时前
基于 Launcher3 的 iOS 风格桌面 04 拖拽和移位
android
2501_915106326 小时前
iOS 反编译防护工具与实战组合 从静态侦察到 IPA 成品加固的工程化路径
android·ios·小程序·https·uni-app·iphone·webview
游戏开发爱好者89 小时前
iOS 26 iPhone 使用记录分析 多工具组合构建全方位设备行为洞察体系
android·ios·小程序·uni-app·cocoa·iphone·webview
zhangphil16 小时前
HARDWARE 属性的Bitmap与普通Bitmap,GPU与RenderThread渲染与处理方式异同比较,Android
android
消失的旧时光-194318 小时前
Flutter 异步编程:Future 与 Stream 深度解析
android·前端·flutter
alexhilton18 小时前
Compose CameraX现已稳定:给Composer的端到端指南
android·kotlin·android jetpack