记一次tcp连接超时的问题分析

现象:
IIS站点下使用Restsharp.dll通过HTTP协议调用远程接口,时常发现调用失败,System.Net返回TCP错误,代码10060,表示超时或无响应。

通过安装Wireshark抓包发现,Client连接服务器的TCP第一次握手,发送SYN失败,导致多次重传,仍然失败后,没有后续的HTTP请求了。

wireshark抓包如图:

图像 2018-8-29,22.34.jpg

分析:

在Client进行抓包,看到上图所示的TCP第一次握手的SYN包进行了多次重传,且最后失败告终。 所以认为可能是客户端的问题,怀疑是不是客户端没能将请求从本机发出。于是做了一下测试:

  1. 同样功能在另外的客户端上,接的第三方的API接口,使用是正常的,并没有出现该错误。(我认为此项可以说明客户端代码无误)
  2. 另外编写一个单独的接口调用程序,放到该服务器上跑,也发现同样的问题,还是TCP第一次的SYN发送失败;

从上面两项测试来看,基本上可以认为Client端程序是正确的,那么怀疑问题出在Server。

深入思考

后面仔细学习了TCP三次握手协议的过程,也在网上找了相关的资料和跟别人交流后,发现,

其实当Client发生SYN重传时,只是说明Client没有收到ACK包,原因有可能是Client没有发出请求,或者Server接收到了SYN但没能发出ACK包。

最直接有效的方法就是同时在Client和Server进行抓包分析。

听到这里,瞬间觉得自己经验还是不够,因为自己是Client端,而由于种种原因Server端的开发也没人配合,所以把自己局限在证明Client没有问题了。

解决

于是,自己同时在Linux Server上和Client抓包,测试重现问题后,发现Server确实接收到SYN包,但是都没有回应ACK包。

最后通过请教一些Linux运维的同事,发现是在Server上开启了 tcp_tw_recycle选项。

关于 tcp_tw_recycle选项,默认是关闭的。 如果开启了,会假设对端网络开启了tcp_timestamps, 然后会比较时间戳,如果时间戳变大了则表示可以重用。

而如果对端是一个NAT网络(如:一个公司只用一个IP出公网),就会出现建立连接的SYN包直接被丢弃的情况,这时对端可能会出现connect timeout的错误。

实际上,在TCP文档上,这个选项是不建议开启的。(当然对于Linux我并不熟悉。。)

关闭选项后,测试,发现问题消失。

虽然是一个简单的事情,但是因为自己及部门等各种原因,折腾了三个星期,在这里做个记录。激励自己多学习,多提高!

对于TCP的知识,可以阅读酷壳上的文章:TCP 的那些事儿(上)

标签: tcp, syn, tcp_tw_recycle, 10060

添加新评论