TCP连接被意外重置的原因

    今天在做服务器压力测试的时候,出现了很奇怪的情况,与服务器建立连接会成功,但是很快会被重置(RESET)掉。花了半天时间,终于找到原因所在,我把过程和结果写下来与大家分享。

 

    服务器正常逻辑是:接受连接,等待用户注册报文,处理其他请求,如果连接一段时间没有活动,则主动关闭连接。

 

    客户端逻辑是:与服务器建立连接后,马上发送注册报文,然后每隔一段时间发送一个请求。有上万个客户端同时连接一个服务器,当连接出现错误时,马上重新连接。

 

    出现错误时,客户端会报告下面一连串错误:

 

recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer
recv: Connection reset by peer

 

    进一步的测试发现只有在客户端数目超过一定数量才会出现这样的情况,于是联想到Linux进程打开文件描述符(Linux下套接字也是一种文件描述符)的数量限制(前几天刚刚增加了这个数量限制),但是到底有什么联系不知道。

 

    开始以为服务器程序逻辑主动关闭了连接,但是根据抓包的结果,服务器根本就没有发送TCP FIN报文,下面是一个典型的连接建立与重置的过程:

 

14:01:03.567888 IP 192.168.6.45.36692 > 192.168.6.46.8080: S 1231228012:1231228012(0) win 5792 <mss 1460,sackOK,timestamp 174530727 168899918,nop,wscale 8>
14:01:03.567969 IP 192.168.6.46.8080 > 192.168.6.45.36692: S 909133089:909133089(0) ack 1231228013 win 5792 <mss 1460,sackOK,timestamp 168900338 174530727,nop,wscale 8>
14:01:03.567978 IP 192.168.6.45.36692 > 192.168.6.46.8080: . ack 1 win 23 <nop,nop,timestamp 174530727 168900338>
14:01:03.568022 IP 192.168.6.45.36692 > 192.168.6.46.8080: P 1:76(75) ack 1 win 23 <nop,nop,timestamp 174530727 168900338>
14:01:03.568110 IP 192.168.6.46.8080 > 192.168.6.45.36692: . ack 76 win 23 <nop,nop,timestamp 168900338 174530727>
14:01:03.568769 IP 192.168.6.46.8080 > 192.168.6.45.36692: R 1:1(0) ack 76 win 23 <nop,nop,timestamp 168900338 174530727>

 

    检查服务器的日志,也没有主动关闭连接的记录,甚至并没有接受到新的连接。这说明连接是由底层协议栈关闭的,但协议栈为什么会主动关闭呢?

 

    用telnet连接服务器,也不正常,但是是被正常关闭的(有正常的FIN序列),而不是重置。

 

    是否与侦听套接字的就绪连接队列长度有关?但是连接队列满时,协议栈不做任何操作,而是让客户端超市重发SYN报文,与出现的情况不一致。

 

    看来还是有打开文件描述符的数量限制有关,那么不能再打开文件描述符时,会出现什么情况呢?为什么telnet连接会出现不同的情形呢?对这些问题的回答就要透过现象看本质了,我的分析如下:

 

    首先,连接确实是建立了,说明协议栈是接受了这个连接的,当然,应用程序肯定没有接受,否则打开文件描述符数目超过上限了。另一方面,协议栈当然要关闭这个连接,但是没有立即关闭,应该是在应用程序接受连接时(accept)关闭(尚未验证),进一步跟踪,accept会产生too many open files错误。这也说明套接字这个文件描述符是在accept时打开的,在协议栈中建立的连接并没有对应的套接字描述符。

 

        telnet连接的不同之处在于没有向服务器发送数据,此时采用正常方式关闭,这是协议的要求还是Linux实现的特例没有考证过。

 

        还有另外一个结论是在accept之前收到的数据仍然会被接受并应答,并且连接上的数据是存储在协议栈中的,这符合我先前的概念。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fighting Horse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值