如果recv()接收到有效负载大小为0的TCP数据包,它将返回什么值?

5
在TCP套接字编程中,如果recv()返回0,则表示对方关闭了连接。然而,据我所知,TCP RFC并没有规定TCP负载必须> 0。因此,理论上,TCP堆栈可以接收大小为0的负载消息。
因此,我的问题实际上是,如果recv()接收到大小为0的数据包,它将返回什么?如果它返回0,那么我们如何将其与关闭连接指示区分开来。
2个回答

11

在实际的 TCP 数据流中,0 负载大小的 TCP 段是无处不在的。它们通常在一方希望确认接收到来自另一方的数据,但自己没有数据要发送时发送。(这些通常被称为“ACK 数据包”,但是“ACK 数据包”只是不包含任何数据的普通段)。

由于这样的数据包不包含任何可传递给用户应用程序的数据,因此它们不会导致 recv() 返回 - recv() 将一直阻塞直到有实际数据到达。如果 recv() 返回 0,则明确表示另一端已关闭其连接并且不再发送任何数据。

请记住,TCP 是面向流的:单个 recv() 调用返回的数据与单个 TCP 段中的数据之间没有一对一的映射关系。一个单独的 recv() 调用可能返回一个覆盖多个 TCP 段的数据块,并且单个 TCP 段中的数据可能在多个 recv() 调用中返回。TCP 段之间的边界对使用 BSD sockets API 的应用程序不可见。如果您想要这样的边界,您需要使用应用层协议在 TCP 流中自行实现,或者使用像 UDP 这样的数据报协议。


ACK数据包将设置一个ACK标志。 - AlastairG
1
@AlastairG:没错,但除了初始的SYN或连接重置之外,每个数据包都设置了ACK位。 - caf
是的,没错,我忘了那个 :) 我不确定他们一定要这样做,但这是一个好习惯。 - AlastairG

3
根据POSIX标准,如果recv返回0,则连接已被对等方正确关闭。
如果有人成功发送了一个零大小负载的TCP数据包,则操作系统不必向在该套接字上被阻塞的recv系统调用的进程返回任何数据。
请记住,TCP负载形成连续流,可能会被操作系统随机切片,而不是必须在单个系统调用期间返回的数据报序列。

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