目录
- 前言
- 一、UnknownHostException
- 1、网络断开验证
- 2、DNS 服务器意外挂掉验证
- 3、DNS 服务器故障验证
- 4、所需诊断信息
- 二、ConnectTimeoutException
- 三、SocketTimeoutException
- 1、子错误 - 读超时
- 2、子错误 - SSL 握手超时
- 3、子错误 - 未知原因
- 四、HttpHostConnectException
- 1、服务器故障验证
- 2、代理服务器故障验证
- 3、所需诊断信息
- 4、参考资料
- 五、NoRouteToHostException
- 六、SSLException
- 1、子错误 - SSL 读期间连接重置
- 2、子错误 - SSL 握手期间连接重置
- 七、SSLHandshakeException
- 1、子错误 - 握手失败
- 2、子错误 - 连接超时
- 3、子错误 - 连接重置
- 4、子错误 - 连接被关闭
- 八、SSLProtocolException
- 1、子错误 - 记录MAC无效的读失败
- 2、子错误 - 协议版本导致的读失败
- 九、NoHttpResponseException
- 十、InterruptedIOException
- 1、子错误 - 连接已关闭
- 十一、IOException
- 1、子错误 - 连接关闭
- 2、子错误 - 请求被终止
- 十二、SocketException
- 1、子错误 - 读消息连接重置
- 2、子错误 - 连接重置
- 3、子错误 - Socket 关闭
- 十三、ConnectException
- 1、子错误 - 连接被拒绝
- 2、子错误 - 主机不可达
- 3、子错误 - 网络不可达
- 十四、ClientProtocolException
- 1、子错误 - 未知原因
前言
注:OkHttp 代码基于 OkHttp 3.4 分析。Android 代码基于 Android 6.0.0_r26 分析。
一、UnknownHostException
错误说明: 域名解析失败。
错误消息: Unable to resolve host “m9.music.126.net”: No address associated with hostname
可能原因:
- 网络断开;
- DNS 服务器意外挂掉;
- DNS 服务器故障。
DNS 服务器挂掉或者故障这种问题比较少见,然而之前确实发生过大范围的DNS 服务器问题。
针对这些原因,我们可以做一些模拟测试。
1、网络断开验证
对于网络连接断开的情况,我们采用如下的方法来模拟测试:
- 关闭手机的 WiFi 和移动网络,也就是使手机处于完全断网的情况;
- 执行一个 HTTP 请求。
以 OkHttp 为例,在请求开始之后,立即就报出了如下的异常:
2、DNS 服务器意外挂掉验证
对于DNS 服务器意外挂掉的情况,我们采用如下的方法模拟测试:
- 连接 WiFi,设置手机的 IP 地址为静态 IP 地址,不修改之前 DHCP 分配的 IP 地址,但设置 DNS 服务器地址为无效的地址;
- 执行一个 HTTP 请求。
以 OkHttp 为例,在请求开始之后,将报出如下的异常:
这个异常与网络断开情况下报出的异常一模一样,然而这一次从请求开始执行到异常报出,经历的时间则要长得多,如我们上面看到的,这段时间长达 40 s。
3、DNS 服务器故障验证
DNS 服务器故障主要是指 DNS 服务器确实查不到所请求的域名,可能是 DNS 服务器出了问题,也可能是为域名做的 DNS 配置还没有生效等。
对于这种情况,我们采用如下方法模拟测试:
- 手机正常连接网络;
- 以一个不存在的域名执行一个 HTTP 请求。
请求执行之后,将报出如下异常:
4、所需诊断信息
依据上面的测试分析,诊断域名解析问题,需要如下诊断信息:
- 请求开始时间;
- 异常报出时间;
- 网络是否连接;
- DNS 服务器 IP 地址列表;
- DNS 服务器是否可用(ping DNS 服务器 IP地址的结果);
- DNS 的结果(nslookup 结果)。
二、ConnectTimeoutException
等价异常类型:
- org.apache.http.conn.ConnectTimeoutException
- com.netease.mam.org.apache.http.conn.ConnectTimeoutException
错误说明: 连接超时
错误消息: Connect to /183.214.133.45:443 timed out
异常分析:
external/apache-http/src/org/apache/http/conn/scheme/PlainSocketFactory.javaconnectSocket()Socket.connect()SocketTimeoutException
可能原因:
- 设备接入的网络本身带宽比较低;
- 设备接入的网络本身延迟比较高;
- 设备与服务器的网络路径中存在比较拥堵、负载比较重的节点;
- 网络中路由节点的临时性异常。
所需诊断信息:
- Traceroute 获取的网络路径信息。
- 网络路径上不同节点的繁忙程度,可通过丢包率来近似地反映。
- 网络连接条件(移动网络/WiFI),网络延时及带宽。
三、SocketTimeoutException
异常: java.net.SocketTimeoutException
错误说明: socket 超时
异常分析:
okhttp3.internal.http2.Http2Stream
java.net.PlainSocketImplaccept(SocketImpl newImpl)ServerSocketChannelImpl
libcore.io.IoBridgelibcore.io.IoBridgeerrnoEAGAIN
external/conscrypt/src/main/native/org_conscrypt_NativeCrypto.cpp
1、子错误 - 读超时
错误消息: Read timed out
异常分析:
external/conscrypt/src/main/native/org_conscrypt_NativeCrypto.cppSSL/TLS
可能原因:
- 设备接入的网络本身带宽比较低;
- 设备接入的网络本身延迟比较高;
- 设备与服务器的网络路径中存在比较拥堵、负载比较重的节点;
- 网络中路由节点的临时性异常。
所需诊断信息:
- Traceroute 获取的网络路径信息。
- 网络路径上不同节点的繁忙程度,可通过丢包率来近似地反映。
- 网络连接条件(移动网络/WiFI),网络延时及带宽。
2、子错误 - SSL 握手超时
错误消息: SSL handshake timed out
异常分析:
external/conscrypt/src/main/native/org_conscrypt_NativeCrypto.cppSSL/TLS
可能原因:
- 设备接入的网络本身带宽比较低;
- 设备接入的网络本身延迟比较高;
- 设备与服务器的网络路径中存在比较拥堵、负载比较重的节点;
- 网络中路由节点的临时性异常。
所需诊断信息:
- Traceroute 获取的网络路径信息。
- 网络路径上不同节点的繁忙程度,可通过丢包率来近似地反映。
- 网络连接条件(移动网络/WiFI),网络延时及带宽。
3、子错误 - 未知原因
错误消息: null
异常分析:
SocketTimeoutException
可能原因:
- 设备接入的网络本身带宽比较低;
- 设备接入的网络本身延迟比较高;
- 设备与服务器的网络路径中存在比较拥堵、负载比较重的节点;
- 网络中路由节点的临时性异常。
所需诊断信息:
- 更加完整的异常堆栈
- Traceroute 获取的网络路径信息。
- 网络路径上不同节点的繁忙程度,可通过丢包率来近似地反映。
- 网络连接条件(移动网络/WiFI),网络延时及带宽。
四、HttpHostConnectException
等价异常类型:
- org.apache.http.conn.HttpHostConnectException
- com.netease.mam.org.apache.http.conn.HttpHostConnectException
错误说明: 客户端的数据包可以到达目标主机,但由于各种原因,连接建立失败的问题。
错误消息: Connection to http://m7.music.126.net refused
可能原因:
- 连接的目标主机没有开对应的端口,可能服务器发生故障
- 客户端设置了代理,而代理进程并没有跑起来。
针对这些原因,我们也可以做一些模拟和测试。
1、服务器故障验证
对于这种情况,我们采用如下的方法来模拟测试,
- 指定我们执行 HTTP 请求时访问的端口为一个无效的端口,如使用 URL ;
- 以 HttpClient 作为我们的 HttpStack 来执行 HTTP 请求。
请求执行之后,将报出如下异常:
org.apache.http.conn.HttpHostConnectException 的 errorMessage
对于同样的问题,如果以 OkHttp 作为 HttpStack 来执行请求的话,则将报出稍有不同的异常:
java.net.ConnectException
2、代理服务器故障验证
这主要是指代理服务器进程没有启动,或代理设置存在问题。
对于这种情况,我们通过如下的方法来模拟测试:
- 使手机连接 WiFi;
- 为手机所连接的 WiFi 设备设置代理,其中代理服务器的地址为无效的 IP 地址,或端口为无效端口;
- 以 HttpClient 作为我们的 HttpStack 来执行 HTTP 请求。
请求执行之后,将报出如下异常:
对于同样的问题,OkHttp 报出了不同的异常:
3、所需诊断信息
为了确认所报出的异常产生的根源,需要下的诊断信息:
- 连接的目标主机的 IP 地址;
- 连接建立的目标端口;
- 用户设置的代理服务器地址和端口;
- TCP 连接目标 IP:端口 的结果。
4、参考资料
针对这个异常,网络上有其它的一些资料和讨论,相关链接如下:
五、NoRouteToHostException
异常: java.net.NoRouteToHostException
错误说明: 无法连接远程地址与端口。
错误消息: No route to host
可能原因:
- 防火墙的规则设置导致数据包无法被发送出去;
- 中间路由节点挂掉。
所需诊断信息:
- 用户防火墙配置;
- 目标主机是否可以访问(ping)。
参考资料:
六、SSLException
异常: javax.net.ssl.SSLException
错误说明: SSL 失败
1、子错误 - SSL 读期间连接重置
错误消息: Read error: ssl=0xf49f7200: I/O error during system call, Connection reset by peer
可能原因:
- 在网络数据传输期间,TCP 连接被服务器异常结束。
- 遭受网络 TCP Reset 攻击。
异常分析:
在网络数据传输期间,TCP 连接意外结束,由于服务器进程意外终止等原因,没有经过正常的 TCP 连接断开过程。后续客户端向服务器发送 TCP 包,如数据包、ACK 包等,服务器返回 RST 包所致。
所需诊断信息:
- 与目标服务器目标端口的 TCP 连接测试结果,检查目标服务器进程是否存活。
参考资料:
2、子错误 - SSL 握手期间连接重置
错误消息: SSL handshake aborted: ssl=0x79c484c0: I/O error during system call, Connection reset by peer
可能原因:
- 在网络数据传输期间,TCP 连接被服务器异常结束。
- 遭受网络 TCP Reset 攻击。
异常分析:
以 Android 6.0.0_r1 为例,仅有的出现 “SSL handshake aborted” 的位置为 http://androidxref.com/6.0.0_r1/xref/external/conscrypt/src/main/native/org_conscrypt_NativeCrypto.cpp — NativeCrypto_SSL_do_handshake()。
NativeCrypto_SSL_do_handshake()throwSSLExceptionWithSslErrors()asprintf()
SSL_do_handshake(SSL s)SSL_do_handshake(SSL s)SSL *sshandshake_funchandshake_funcSSL_set_accept_state()sslmethodssl_acceptSSL_set_connect_state()sslmethodssl_connectSSL *sSSL_PROTOCOL_METHOD *methodNativeCrypto_SSL_new()SSL_new()SSL_PROTOCOL_METHOD *methodSSL_CTXNativeCrypto_SSL_CTX_new()SSLv23_method()TLS_method(void)protocol_methodTLS_protocol_method
s->handshake_funcssl3_connect(SSL *s)ssl3_connect(SSL *s)
ssl3_connect(SSL *s)
所需诊断信息:
- 与目标服务器目标端口的 TCP 连接测试结果,检查目标服务器进程是否存活。
七、SSLHandshakeException
异常: javax.net.ssl.SSLHandshakeException
错误说明: SSL/TLS 握手失败
1、子错误 - 握手失败
错误消息: Handshake failed
可能原因:
- 握手失败,证书验证失败
- 未知证书颁发者;
- 不完整的证书链;
- 自签名证书;
- 服务器主机名不匹配;
- 严格安全重新协商失败;
- 遭遇了中间人攻击。
- 握手失败,协议协商失败/握手格式不兼容
- 协议异常,服务器名称标识不匹配
- 某些版本 SSL 库的 bug
所需诊断信息:
- 异常的详细错误消息;
- 客户端支持的 SSL/TLS 版本;
- 客户端设置的 SNI 信息;
- 服务器下发的证书链;
- 客户端可用的加密套件。
证书链消耗流量可能会比较大,大概在几 KBytes
2、子错误 - 连接超时
错误消息: SSL handshake aborted: ssl=0xeec6d600: I/O error during system call, Connection timed out
可能原因:
- 设备接入的网络本身带宽比较低;
- 设备接入的网络本身延迟比较高;
- 设备与服务器的网络路径中存在比较拥堵、负载比较重的节点;
- 网络中路由节点的临时性异常。
所需诊断信息:
- Traceroute 获取的网络路径信息。
- 网络路径上不同节点的繁忙程度,可通过丢包率来近似地反映。
- 网络连接条件(移动网络/WiFI),网络延时及带宽。
3、子错误 - 连接重置
错误消息: SSL handshake aborted: ssl=0xea0e4f00: I/O error during system call, Connection reset by peer
可能原因:
- 在网络数据传输期间,TCP 连接被服务器异常结束。
- 遭受网络 TCP Reset 攻击。
错误原因分析:
在网络数据传输期间,TCP 连接意外结束,可能由于服务器进程意外终止等原因,没有经过正常的 TCP 连接断开过程。后续客户端向服务器发送 TCP 包,如数据包、ACK 包等,服务器返回 RST 包所致。
所需诊断信息:
- 与目标服务器目标端口的 TCP 连接测试结果,检查目标服务器进程是否存活。
4、子错误 - 连接被关闭
错误消息: Connection closed by peer
可能原因:
- 在网络数据传输期间,TCP 连接被服务器异常结束。
错误原因分析:
在网络数据传输期间,由于服务器回收 TCP 连接,或服务器进程意外结束,连接被提前结束,正常的 TCP 连接断开过程完成所致。
所需诊断信息:
- 与目标服务器目标端口的 TCP 连接测试结果,检查目标服务器进程是否存活。
八、SSLProtocolException
异常: javax.net.ssl.SSLProtocolException
错误说明: 协议异常
1、子错误 - 记录MAC无效的读失败
错误消息:
可能原因:
- 数据在传输过程中被篡改。
- MAC 方式不支持。
- 某些版本SSL 库的 bug。
所需诊断信息:
- 客户端支持的 SSL/TLS 版本;
- 客户端可用的加密套件。
2、子错误 - 协议版本导致的读失败
错误消息: Read error: ssl=0xdbab7300: Failure in SSL library, usually a protocol error error:100c542e:SSL routines:ssl3_read_bytes:TLSV1_ALERT_PROTOCOL_VERSION (external/boringssl/src/ssl/s3_pkt.c:972 0xd3fb2d20:0x00000001)
可能原因:
- 遭遇降级攻击;
- 某些版本 SSL 库的 bug。
所需诊断信息:
- 客户端支持的 SSL/TLS 版本;
- 服务器下发的证书链;
- 客户端可用的加密套件。
证书链消耗流量可能会比较大,大概在几 KBytes
九、NoHttpResponseException
等价异常类型:
- org.apache.http.NoHttpResponseException
- com.netease.mam.org.apache.http.NoHttpResponseException
错误说明: 服务器响应异常
错误消息: The target server failed to respond
可能原因:
- 服务器故障。
十、InterruptedIOException
异常: java.io.InterruptedIOException
错误说明: IO 中断
1、子错误 - 连接已关闭
错误消息: Connection has been shut down.
异常分析:
external/apache-http/src/org/apache/http/impl/conn/AbstractClientConnAdapter.javaassertNotAborted()
可能原因:
客户端在发送请求或接收响应时,发现连接已经被终止,请求被终止/取消。
IOException
异常: java.io.IOException
错误说明: IO 失败
十一、IOException
异常: java.io.IOException
错误说明: IO 失败
1、子错误 - 连接关闭
错误消息: Connection already shutdown
异常分析:
external/apache-http/src/org/apache/http/impl/conn/DefaultClientConnection.javaopening()
可能原因:
- 连接打开动作执行过程中,被客户端关闭,请求被终止/取消。
2、子错误 - 请求被终止
错误消息: Request already aborted
异常分析:
external/apache-http/src/org/apache/http/client/methods/HttpRequestBase.javasetConnectionRequest()setReleaseTrigger()ConnectionReleaseTrigger
可能原因:
- 请求被终止/取消。
十二、SocketException
异常: java.net.SocketException
错误说明: Socket 异常
1、子错误 - 读消息连接重置
错误消息: recvfrom failed: ECONNRESET (Connection reset by peer)
可能原因:
- 在网络数据传输期间,TCP 连接被服务器异常结束。
- 遭受网络 TCP Reset 攻击。
错误原因分析:
在网络数据传输期间,TCP 连接意外结束,由于服务器进程意外终止等原因,没有经过正常的 TCP 连接断开过程。后续客户端向服务器发送 TCP 包,如数据包、ACK 包等,服务器返回 RST 包所致。
所需诊断信息:
- 与目标服务器目标端口的 TCP 连接测试结果,检查目标服务器进程是否存活。
2、子错误 - 连接重置
错误消息: Connection reset
可能原因:
- 在网络数据传输期间,TCP 连接被服务器异常结束。
- 遭受网络 TCP Reset 攻击。
错误原因分析:
在网络数据传输期间,TCP 连接意外结束,可能由于服务器进程意外终止等原因,没有经过正常的 TCP 连接断开过程。后续客户端向服务器发送 TCP 包,如数据包、ACK 包等,服务器返回 RST 包所致。
所需诊断信息:
- 与目标服务器目标端口的 TCP 连接测试结果,检查目标服务器进程是否存活。
3、子错误 - Socket 关闭
错误消息: Socket closed
异常分析:
异常抛出的位置为 libcore/luni/src/main/java/libcore/io/IoBridge.java 的 isConnected()。
可能原因:
- 连接被客户端关闭,请求被终止/取消。
十三、ConnectException
异常: java.net.ConnectException
错误说明: 连接失败
异常分析:
ConnectExceptionlibcore.io.IoBridgeconnect(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs)isConnected()socketerrnoerrnoerrno
1、子错误 - 连接被拒绝
错误消息: failed to connect to /119.84.111.126 (port 80) after 30000ms: isConnected failed: ECONNREFUSED (Connection refused)
HttpHostConnectException
2、子错误 - 主机不可达
错误消息: failed to connect to /153.101.65.23 (port 80) after 30000ms: isConnected failed: EHOSTUNREACH (No route to host)
可能原因:
- 防火墙的规则设置导致数据包无法被发送出去;
- 中间路由节点挂掉。
异常分析:
引发了ICMP目的不可达错误,这认为是软错误。client核心保存消息并且荏苒发送SYN。。如果超出一个确定的时间。保存的ICMP错误返回给进程 EHOSTUNREACH或者ENETUNREACH。ENETUNREACH被认为是过时的。所以返回的应该是EHOSTUNREACH。
所需诊断信息:
- 用户防火墙配置;
- 目标主机是否可以访问(ping)。
3、子错误 - 网络不可达
错误消息: failed to connect to /59.111.160.195 (port 80) after 30000ms: connect failed: ENETUNREACH (Network is unreachable)
可能原因:
- 防火墙的规则设置导致数据包无法被发送出去;
- 中间路由节点挂掉。
所需诊断信息:
- 用户防火墙配置;
- 目标主机是否可以访问(ping)。
十四、ClientProtocolException
等价异常类型:
- com.netease.mam.org.apache.http.client.ClientProtocolException
错误说明: 协议错误
异常分析:
external/apache-http/src/org/apache/http/impl/client/AbstractHttpClient.javaexecute()RequestDirector.execute()HttpExceptionHttpException
external/apache-http/src/org/apache/http/impl/client/DefaultRequestDirector.javacreateTunnelToTarget()external/apache-http/src/org/apache/http/impl/conn/ProxySelectorRoutePlanner.javadetermineProxy()external/apache-http/src/org/apache/http/impl/conn/ProxySelectorRoutePlanner.javadetermineProxy()
1、子错误 - 未知原因
错误消息: null
可能原因:
- 这个错误主要与客户端的 HTTP 代理服务器设置有关。
所需诊断信息:
- 如果是 HTTPS 请求,通过 HTTP 的 CONNECT 方法建立隧道链接时,CONNECT 请求的完整响应内容。
- 代理服务器配置。