TCP 发送RST分节的情况,关闭时 recv buffer 不为空,则发送RST分节

今天在写一个客户端,连接服务器模拟器的程序的时候碰到了一个小问题。 交互的顺序大概是这样的。

整个过程中TCP 客户端和服务端的读写全部使用阻塞模式。


 Client                                                         Server

1, 客户端发起请求, 并发送请求A                 服务器接受请求后,并没有读取客户端发送的任何数据,而是直接发送数据。发送完毕后直接关闭socket.

2,客户端发送请求完毕后, 读socket, 读取完server 发送的数据后,出现

Connection reset by peer。 Connection reset by peer (Errno::ECONNRESET)。


如果修改服务器程序,使得服务器程序读取完客户端的请求之后, 才发送数据,然后关闭连接。

则客户端read可以返回正常的0,表明服务器程序正常关闭连接。


开始怀疑这是协议栈的,design intention, 如果关闭socket时,recv buffer中不为空,仍有滞留数据。则发送reset分节,而不是正常的四次握手关闭连接。

同时在网上,也找到了类似的文章说明。



正常情况tcp四层握手关闭连接,rst基本都是异常情况,整理如下:

1. GFW 

2. 对方端口未打开,发生在连接建立

   如果对方sync_backlog满了的话,sync简单被丢弃,表现为超时,而不会rst

3. close Socket 时recv buffer 不为空

  例如,客户端发了两个请求,服务器只从buffer 读取第一个请求处理完就关闭连接,tcp层认为数据没有正确提交到应用,使用rst关闭连接。

3. 移动链路

      移动网络下,国内是有5分钟后就回收信令,也就是IM产品,如果心跳>5分钟后服务器再给客户端发消息,就会收到rst。也要查移动网络下IM 保持<5min 心跳。

4. 负载等设备

      负载设备需要维护连接转发策略,长时间无流量,连接也会被清除,而且很多都不告诉两层机器,新的包过来时才通告rst。

   Apple push 服务也有这个问题,而且是不可预期的偶发性连接被rst;rst 前第一个消息write 是成功的,而第二条写才会告诉你连接被重置,

  曾经被它折腾没辙,因此打开每2秒一次tcp keepalive,固定5分钟tcp连接回收,而且发现连接出错时,重发之前10s内消息。

5. SO_LINGER 应用强制使用rst 关闭

    该选项会直接丢弃未发送完毕的send buffer,可能造成业务错误,慎用; 当然内网服务间http client 在收到应该时主动关闭,使用改选项,会节省资源。

  好像曾经测试过haproxy 某种配置下,会使用rst关闭连接,少了网络交互而且没有TIME_WAIT 问题

6. 超过超时重传次数、网络暂时不可达

7. TIME_WAIT 状态

  tw_recycle = 1 时,sync timestamps 比上次小时,会被rst

7. 设置 connect_timeout

     应用设置了连接超时,sync 未完成时超时了,会发送rst终止连接。

8. 非正常包

  连接已经关闭,seq 不正确等

9. keepalive 超时

    公网服务tcp keepalive 最好别打开;移动网络下会增加网络负担,切容易掉线;非移动网络核心ISP设备也不一定都支持keepalive,曾经也发现过广州那边有个核心节点就不支持。

10. 待整理

参考:

setsockopt :SO_LINGER 选项设置(转)

原 几种TCP连接中出现RST的情况

猜你喜欢

转载自blog.csdn.net/abccheng/article/details/73863207