在没有 SO_LINGER > 0 的情况下强制关闭服务器端套接字可能会丢失数据,对吧?

Forced server-side socket close without SO_LINGER > 0 can lose data, right?

本文关键字:套接字 服务器端 对吧 数据 LINGER SO gt 情况下      更新时间:2023-10-16

我正在编写一个使用套接字的跨平台客户端应用程序,它是用C++编写的。我遇到了问题,服务器在向我发送信息后,正在对套接字进行硬关闭。

我一直在阅读关于这个主题的其他帖子,我对这种方法的对错不太感兴趣,但似乎服务器要么明确设置了so_LINGER=0,要么这是该系统上的默认行为(不确定,这是一个Linux盒子)。

我可以看到(在Wireshark中)数据在毫秒内被发送给我,然后是RST,表明服务器硬关闭。我个人不同意这种方法,因为应该由客户端关闭套接字。

服务器团队表示,这种方法没有错(进行硬关闭而不是关闭),这在服务器上是典型的,以避免累积TIMED_WAIT套接字。在Windows上,我的select()返回指示有内容要读取(而我还没有读取任何"传输中"数据)。

然而,由于RST的快速到达,在Windows上,recv()返回-1,我看到错误代码为10054(对等重置连接)。如果我至少能得到发送的数据,这不会太糟糕,但似乎一旦我的客户端的套接字堆栈看到RST,任何未读字节都不再对我可用。

在Linux(客户端)上,没有问题。TCP堆栈的行为似乎略有不同,因为我可以在RST被执行之前读取未完成的字节。我很难说服服务器人员他们有一个错误,因为它适用于Linux客户端。

首先,我说得对吗?这是服务器端的问题吗?我看不出客户端做错了什么,所以它一定是对的?

服务器团队似乎坚持他们想执行关闭,而且他们不想有TIMED_WAIT,所以我想让他们添加一个so_LINGER,比如2秒?这听起来能解决我的问题吗?据我所知,这将阻止服务器在发送数据后这么快发送RST,并应该给我一个读取未处理字节的机会。

找到了我自己问题的明确答案:

"…一旦接收到RST段,接收方将立即中止连接。这句话的含义不仅仅是意味着你将无法接收或向该连接发送更多数据。它还意味着TCP接收缓冲区中的任何未读数据都将丢失…"它引用了《TCP/IP互联第二卷》一书。我没有那本书,所以我只能相信他的话。在Linux上似乎没有丢弃数据,只有Windows。。。

Olivier Langlois的博客

篡改SO_LINGER以强制重置的副作用是丢失所有挂起的数据。事实上,你没有收到它,这就是你需要的所有证据,证明服务器团队这样做是错误的。

下面引用的RFC 793说"这个命令[ABORT]导致所有挂起的SEND和RECEIVE被中止。。。以及一个特殊的RESET消息发送到连接另一侧的TCP另请参见W.R.Stevens,TCP/IP图解,第1卷,第287页:"中止连接为应用程序提供了两个功能:(1)任何排队的数据都会被丢弃,重置会立即发送;(2)RST的接收器可以判断出另一端进行了中止,而不是正常关闭。"。在第2卷中也有类似的措辞,以及实现它的BSD代码的摘录。

TIME_WAIT状态只发生在接收到FIN之前发送FIN的套接字上:请参阅RFC 793。因此,服务器应该等待来自客户端的FIN,并有适当的超时,而不是重置。这也将允许客户端进行连接池。