在 TCP 套接字编程中,如果recv()
返回 0,则表示对方关闭了其连接。但是,AFAIK,TCP RFC 不要求 TCP 的有效负载大于 0。因此,理论上,TCP 堆栈可以接收有效负载为 0 的消息。
所以,基本上我的问题是,recv()
如果它接收到一个大小为 0 的有效载荷数据包会返回什么?如果它返回 0,那么我们如何将它与关闭的连接指示区分开来。
有效载荷大小为 0 的 TCP 段无处不在——它们几乎出现在每个现实世界的 TCP 流中。每当一方希望确认收到来自另一方的数据但没有自己的数据要发送时,它们就会被发送。(这些通常称为“ACK 数据包”,但“ACK 数据包”只是一个恰好不包含数据的常规段)。
由于此类数据包不包含任何要传递给用户应用程序的数据,因此它们不会导致recv()
返回 -recv()
将继续阻塞,直到一些实际数据到达。如果recv()
返回 0,则明确表明另一端已关闭其一侧的连接并且不会再发送任何数据。
请记住,TCP 是面向流的:单个调用返回的数据与单个 TCP 段中的数据之间没有一对一的映射。recv()
单个recv()
调用可能会返回一个与多个 TCP 段重叠的数据块,而单个 TCP 段中的数据可能会在多个recv()
调用中返回。使用 BSD 套接字 API 的应用程序看不到 TCP 段之间的边界。如果你想要这样的边界,你需要在 TCP 流中使用应用层协议来实现自己,或者使用像 UDP 这样的面向数据报的协议。
对,根据 POSIX 如果recv
返回0
,则连接被对等方正确关闭。
如果有人设法发送了一个大小为零的 TCP 数据包,则操作系统不必向recv
在该套接字上的系统调用中被阻止的进程返回任何数据。
请记住,TCP 有效负载形成一个连续的流,可以由操作系统随机切片,而不是在单个系统调用期间必须返回的数据报序列。