网络的一些问题梳理

在做压力测试时,压力客户端的并发高时,压测客户端会在socket.read()时有少量的Connection reset报错,占比0.1%左右。

在客户端机器上,通过对客户端和应用服务端之间的连接进行抓包后发现,所有的请求都是短tcp连接,一次交易是从tcp syn握手开始,到fin挥手结束。

但是又发现一个异常现象,成功的交易请求中,服务端发送了fin包后面还会再发一次rst包;少量失败的交易请求中,服务端在还未发送fin包之前就发送rst包。

通过对成功交易请求的观察,假设所有交易请求都是以fin包后跟一个rst包来关闭连接,那为什么会有少量的fin包之前就发送rst包失败请求呢?

在对压测客户端和压测应用服务端同时抓包后发现,对比失败交易请求的两侧包的顺序后发现,压测应用服务机器先发了fin包再发rst包,但是压测客户端接收的顺序是先接收到rst包再接收到fin包。

对比了多个失败请求后都是这种情况,推测了以下假设:

  1. 并发高时,fin包和rst包的顺序有很低的可能性发生错乱;
  2. tcp协议实现在处理rst包时没有检查seq(虽然rst也占用了一个seq号码),直接就把seq不连续的rst进行了处理

现在还有个疑问,为什么应用服务在关闭tcp连接时会先发一个fin再发一个rst?

通过搜索后发现一个SO_LINGER的参数,这个参数可以控制tcp连接在close时,如果还有数据未发送完,应该怎么处理:

  1. 默认情况下,即不设置SO_LINGER,调用close时,将残留在socket发送缓冲区的数据全部发送出去并等待确认到达,才发送fin包进行四次挥手;
  2. 开启SO_LINGER,调用close时,立即发送RST包进行关闭tcp连接,这种方式称为硬关闭;
  3. 开启SO_LINGER,调用close时,将残留在socket发送缓冲区的数据全部发送出去并睡眠一段时间,如果有ACK就正常再发送FIN包开始4次挥手关闭,否则发送RST,这种方式称为优雅关闭。
    参考:https://blog.csdn.net/xiaokaige198747/article/details/75389113
    从应用逻辑的代码中确实找到了设置SO_LINGER的代码,为上述第2种处理方式。

所以猜测问题在于这个地方。

posted @ 2023-09-12 15:48  bug批发零售  阅读(50)  评论(0)    收藏  举报