smack exception: No response from the server (注意:不是No response from server)
产生的原因有多种:
1. MessageListener未能正确处理response,详情参见
http://community.igniterealtime.org/thread/33598
2. 网络连接出现问题,smack客户端没办法收到response,详情参见(需爬墙……)
http://davanum.wordpress.com/2007/12/31/android-just-use-smack-api-for-xmpp/
今天在服务器上重现了这个问题,间歇性返回No response from the server,但是网络连接状态相当好,到该服务器的http请求都顺利返回,而且速度很快,因此不是网络连接问题。同样,并不是每次返回都报错,60% 的尝试是能够成功的,因此也排除原因1
重现该exception的时候,虽然不是网络导致的原因,但是跟网络环境有密切关联:
1. 在非常稳定的网络环境下(ping值稳定在5ms左右,且没有明显的抖动)出现的概率非常小
2. 在网络抖动比较大的环境下,出现非常频繁
google说明,smack的这个exception,已经report在openfire和ejabberd上都重现过,因此证明,不是单一服务器代码的问题
通过检查smack源代码,查到No response from the server的exception出现在2个文件中:
NonSASLAuthentication.java:
- IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
- if (response == null) {
- throw new XMPPException("No response from the server.");
- }
SASLAuthentication.java:
- Bind response = (Bind) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
- ollector.cancel();
- if (response == null) {
- throw new XMPPException("No response from the server.");
- }
- IQ ack = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
- collector.cancel();
- if (ack == null) {
- throw new XMPPException("No response from the server.");
- }
问题缩小到2个方面:resource bind失败,或者确实没有收到response包
由于这边的服务器采用的是NonSASL验证的方式,所以答案只剩下:确实没有收到response
在服务器上运行tcptrack,监控进入的连接,发现smack报错的时候,tcptrack的连接记录说明,该连接被reset了,也就是说,直接从syn-ack状态跳到了reset状态,因此客户端的连接直接就断开了,所以根本不可能收到response
而smack是个高度封装的库,可配置的参数非常有限,出了用户名和密码以外,跟底层链路相关的参数就只有:SecurityMode,初步判断 是该参数影响了连接,因此更改默认的enable为disable,也就是不使用TLS链路跟服务器进行通信。同样,服务器也禁用TLS之后,问题状况立 即得到改善。
结论:
TLS在TCP连接的基础上,需要消耗更多的网络资源和服务器资源,来进行加密运算,因此在网络抖动非常大,或者网络比较不稳定的状况下,会严重 影响通信连接,尤其是不停的断开重连,如果发现smack客户端有出现No response from the server的exception,可尝试更改连接选项,disable TLS来解决问题