为什么TCP套接字在接收到不正确的ACK时发送RST数据包而不是重新发送数据

Why TCP socket send a RST packet instead of resending data when receives an incorrect ACK?

本文关键字:数据包 RST 数据 新发送 套接字 TCP ACK 不正确 为什么      更新时间:2023-10-16

TPC连接的一个"酷"之处是数据不会丢失。当数据未得到确认时,TCP应该重新发送数据。

我有一个用c++编写的经典游戏服务器,客户端用Flash AS3编写。

在客户端中,我添加了一个检查器工具,它尝试每X秒连接一次YouTube和Twitter,超时时间为5秒。问题是,客户端的互联网连接在几秒钟内断开后(互联网检查器收到1或2次超时,但之后收到OK),它开始从服务器接收数据,但服务器停止从客户端接收数据。

这是TCPDUMP接收到的流量:

1. server > client: Flags [P.], seq 2374:2378, ack 119, win 14600, length 4
2. client > server: Flags [.], ack 2374, win 15524, length 0
3. client > server: Flags [.], ack 2378, win 15520, length 0
. [Here the client sends data to the server, but the server never receives it...]
4. server > client: Flags [P.], seq 2378:2383, ack 119, win 14600, length 5
5. server > client: Flags [P.], seq 2386:2389, ack 119, win 14600, length 3
6. client > server: Flags [.], ack 2386, win 15512, length 0
7. client > server: Flags [.], ack 2389, win 15509, length 0
8. client > server: Flags [R.], seq 127, ack 2389, win 0, length 0

正如您所读到的,当服务器发送带有错误ACK的数据时,客户端在重新发送数据之前会发送RST数据包(迫使服务器关闭连接)。在客户端日志中,我可以看到它接收和处理服务器发送的数据(因此,当服务器发送错误的ACK时,连接不会关闭)。

当TCP在接收到不正确的ACK后决定发送RST数据包而不是重新发送数据时?

客户端套接字是这样定义的AS3Socket

var socket:Socket = new Socket();

并且服务器套接字被设置为具有fcntl()的非阻塞。还有以下选项:

setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *)&dummyint, sizeof(int));
setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&dummyint, sizeof(int));

注意,转储中似乎缺少一个额外的数据包,即服务器字节2383-2385,尽管客户端似乎确实看到了它们,因为它确认了它们。

服务器没有回复错误的ACK。它用它在流中看到的最后一个字节号#119的ACK进行回复。当服务器在一段时间后未能确认这些丢失的字节时,由客户端重新传输这些字节。相反,它正在发送RST。

没有时间信息,但我不得不猜测RST来自于信息重新传输之前客户端上的超时。

TCP本身并不"不稳定",它是一种协议。如果有什么不稳定的地方,那就是你的网络连接。TCP有一种在不稳定的网络上重试的算法。也有可能你的代码出了问题,也有可能是一个中间设备使你的连接超时。