5

我正在编写一个使用套接字的跨平台客户端应用程序,用 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,并且应该让我有机会读取未完成的字节。

4

2 回答 2

1

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

“...在接收到 RST 段后,接收方将立即中止连接。该声明的含义不仅仅是意味着您将无法从该连接接收或发送任何更多数据。它还意味着任何仍在 TCP 接收缓冲区中的未读数据都将丢失……”它引用了《TCP/IP Internetworking Volume II》一书。我没有那本书,所以我只能相信他的话。似乎没有丢弃 Linux 上的数据,只有 Windows ......

Olivier Langlois 的博客

于 2012-11-24T22:45:56.543 回答
1

摆弄 SO_LINGER 以强制重置的副作用是所有待处理的数据都会丢失。您没有收到它的事实就是您需要证明服务器团队这样做是错误的。

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

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

于 2012-11-24T18:28:24.810 回答