当TCP套接字收到错误的ACK时,为什么会发送RST数据包而不是重新发送数据?

4
TPC连接的“酷”之处在于数据不会丢失。当数据没有被ACK确认时,TCP理论上会重新发送数据。
我有一个用c++编写的经典游戏服务器,客户端是用Flash AS3编写的。
在客户端中,我添加了一个检查工具,每X秒尝试使用5秒的超时时间连接到YouTube和Twitter。问题在于当客户端的Internet连接断开几秒钟(Internet检查器接收1或2个超时),之后开始从服务器接收数据,但服务器停止从客户端接收数据。
这是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数据包而不是重新发送数据时?
客户端套接字是以以下方式定义的AS3 Socket
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));

1
这件事情并没有“应该”的成分。它确实会重新发送数据。你认为哪个更可能:在一个拥有30年开发历史、全球互联网广泛部署并在大量平台上经过验证稳定,有数百万用户的协议中出现了bug,还是在你全新未经验证的代码中出现了bug?如果你想解决问题,我建议你在这里发布评论,而不仅仅是猜测。但是从你发布的内容来看,似乎你甚至都没有问一个真正的问题。 - user207421
我并不是在说一个拥有30年历史的协议有漏洞...我不是那种人 :-/ 我是在说似乎有时 TCP 决定发送 RST 数据包而不是重新发送数据,而我不知道为什么。我需要知道为什么会出现这种情况,以便我可以解决它。我将编辑帖子,使其更清晰明了。 - Jorge Fuentes González
我明白了。抱歉,我的英语不够好。当我写的时候,它听起来没有你告诉我那么糟糕,那是因为我编辑过它。而且我仍然考虑“应该”,因为tcpdump显示它没有重新发送数据。谢谢您的评论。 - Jorge Fuentes González
你的(尚未展示的)代码是否也修改了SO_LINGER选项? - user207421
不,我的代码只修改你所看到的内容。这段代码大约有9k行,其余的行是“send”、“recv”和客户端/服务器处理数据,我不会粘贴9k行。在使用C++之前,我用Ruby编写了服务器,并且也遇到了同样的问题。问题出在TCP上,与代码无关。 - Jorge Fuentes González
显示剩余2条评论
2个回答

4
请注意,抓包中似乎缺少一个额外的数据包,即服务器字节2383-2385,但客户端似乎看到了它们并确认收到。
服务器没有回复错误的ACK,而是回复了它在流中看到的最后一个字节号码#119的ACK。 当服务器在一段时间后未能对它们进行ACK时,由客户端重传这些丢失的字节。 然而,客户端没有采取这种方式,而是发送了RST信号。
虽然没有时间信息,但我猜测RST是由于客户端在信息应该被重新传输之前超时引起的。

好的,我现在明白了。我跟踪了更多的数据包,发现服务器字节很奇怪,在所有这些情况发生之前,它发送了“字节2261:2324”,并接收到ACK和第三个ACK“2328”,因此似乎在发送/接收数据时出现了更多问题。我检查了时间,是的,RST数据包是在服务器发送最后一条信息后3秒钟收到的,所以这是可能的。谢谢。 - Jorge Fuentes González

2

TCP并非本质上“不稳定”,它是一个协议。如果有什么不稳定,那就是你的网络连接。TCP有一种算法可以在不稳定的网络上进行重试。同时,你的代码可能存在问题,还有可能是中间设备超时导致连接失败。


是的,我知道TCP只是一种协议。不稳定是指创建的套接字,因此是连接。我认为第三方不会终止连接,因为当客户端在发送服务器未接收到的数据后收到不正确的ACK时,会收到RST数据包。 - Jorge Fuentes González

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接