为什么RST数据包不需要TIME_WAIT状态?

4

我知道TIME_WAIT是为了防止延迟的数据片段被误解为属于随后的连接而设置的。在连接处于TIME_WAIT等待状态时到达的任何数据片段都会被丢弃。

在我的实验中,当客户端发送RST数据包而不是FIN数据包时,我看不到TIME_WAIT。为什么?

服务器

while (1) {
    int len = sizeof(struct sockaddr);
    fd = accept(sfd, &remote, &len);

    read(fd, buf, sizeof(buf));

    strcpy(buf, "Hello Client");
    write(fd, buf, strlen(buf));

    close(fd);
}

客户端

res = connect(sfd, result->ai_addr, result->ai_addrlen);

strcpy(buf, "Hello Server!");
write(sfd, buf, strlen(buf));

close(sfd);

注意: 客户端发送 RST 而不是 FIN,因为它在关闭套接字之前没有读取服务器已发送的缓冲数据。

2个回答

2
当你使用close(2)关闭一个有待接收数据的连接时,由于你没有读取所有待处理数据(可能在缓冲区、已确认、未确认或只是在传输中),因此会破坏状态机,这就引发了一个RST(它会从你的主机发送到连接的另一端,响应到达该连接这一侧的任何数据段)。如建议的那样,如果阅读RFC文档,则连接处于错误状态,并将回复每个数据包的RST帧……它不再处于TIME_WAIT状态。
在读取EOF(即当你已经从另一端接收到FIN)之前调用close(2)是协议错误,因为接收方(即你)正在丢失传输到你这一侧的剩余数据。你可以使用系统调用shutdown(2)来表示你不想再写入更多数据(半关闭发送方),并允许等待剩余数据到达,它会强制你的一侧向另一侧发送一个FIN并将连接置于FIN_WAIT1状态(等待你的FIN和/或另一侧的FIN&ACK)。
注意:TIME_WAIT状态是为确保任何在传输中的数据包有足够的时间到达目的地并得到正确处理而设立的状态。由于连接失败,两端都处于不同步状态,因此等待任何数据包到达都没有意义,因为它们无法被正确处理。对于RST不会发送任何数据包,连接通常会进入CLOSED状态。
RFC-793明确指出: 第3.4节 建立连接 [...]
Reset Processing

In all states except SYN-SENT, all reset (RST) segments are validated
by checking their SEQ-fields.  A reset is valid if its sequence number
is in the window.  In the SYN-SENT state (a RST received in response
to an initial SYN), the RST is acceptable if the ACK field
acknowledges the SYN.

The receiver of a RST first validates it, then changes state.  If the
receiver was in the LISTEN state, it ignores it.  If the receiver was
in SYN-RECEIVED state and had previously been in the LISTEN state,
then the receiver returns to the LISTEN state, otherwise the receiver
aborts the connection and goes to the CLOSED state.  If the receiver
was in any other state, it aborts the connection and advises the user
and goes to the CLOSED state.

因此,正如您所读到的...在任何情况下都没有RSTTIME_WAIT状态。

1
为什么“RST”不需要“TIME_WAIT”状态?“RST”数据包也可能在网络中延迟。因此,我认为“TIME_WAIT”是必要的。 - Pengcheng
“RST”数据包在网络中可能会被延迟甚至丢失。没有人会等待“RST”数据包。等待“RST”数据包是没有意义的。“RST”数据包被发送到另一端,以通知两个参与方之间的不同步状态。您不必等待它们。 - Luis Colorado
@Pengcheng,不是的...当你收到一个RST数据包时,你不会从另一端收到任何其他的RST数据包...你可能会丢失它,但不会延迟接收它...你只会收到一个...如果你因为RST而切换到TIME_WAIT,你将不会收到更多的RST数据包(也不会收到FINACK,其序列号超过连接中接收到的序列号)。此外,如果你收到了一个RST,因为第三方注入了数据段,你必须确认错误的数据(被注入的数据)给对方,并将其视为有效。 - Luis Colorado
你可以延迟接收它...但你只会收到一个...那么如何在接收端检测到它的延迟呢?你无法。RST仅表示另一端正在放弃连接(它进入了关闭状态)。如果你坚持发送更多数据,你将会收到(作为协议中LISTEN部分的一部分)另一个RST,直到你真正理解连接已经断开且没有修复的机会。 - Luis Colorado
我们可以在这个问题上争论几十年。但是TCP已经存在了将近35年,没有人说RST需要切换到TIME_WAIT状态(因为没有连接状态,因为两端不同步,所以我认为CLOSED状态是适当的)。如果您不同意,请写信给IETF修改RFC-793,而不是试图说服我一些无用且不正确的东西。 - Luis Colorado
显示剩余4条评论

0

因为它说明并不存在这样的连接,其效果是在不产生影响的情况下终止它。

换句话说,因为RFC 793明确指出,在接收到RST时不发送任何响应,并且必须进入CLOSED状态(除了某些与连接建立相关的情况,此时你会再次进入LISTEN状态)。


顺便提一下,RST确实是连接的一部分,它必须遵守连接中断点的串行序列号以及到目前为止收到的确认。如果它在窗口内没有失败,那么它必须被忽略,因为是伪造的。事实上,使用加密安全的初始序列号的原因是为了避免DOS攻击,这种攻击利用可预测的序列号发送RST段并中断连接。 - Luis Colorado

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