使用 recv(n) 时,当 n 大于 MTU 时,您是否保证至少读取整个第 2 层帧?

When using recv(n), with n greather than the MTU are you guaranteed to read at least a whole layer 2 frame?

我在想,想象一下,如果没有数据可从 TCP 套接字读取,那么一整帧 1492 字节(已满)到达。在你的代码(C 或任何支持 TCP 的语言)中,你假设 recv 4096 字节,OS 是否保证 recv 读取整个 1492 字节,或者是否有可能在内存和 recv 中加载帧是“交错”的,所以 recv 可能会变少?

TCP 是一种面向流的协议。数据是按顺序接收的,但是在接收到所有数据之前,您不能假设必须调用 recv 的次数。
重复调用 recv 取决于你的应用程序,直到你知道你已经收到你需要的东西。

(1) TCP 是面向流的协议。这意味着它接受来自发送方上层的数据流和 returns 接收方上层的数据流。 TCP 本身从 IP 层接收数据包,然后重建流。那就是在某些时候数据包不复存在。从理论上讲,在这个重建流的某个地方,只有一半的传入数据包被复制到缓冲区中是可能的,但在我看来这不太可能发生。

现在,linux man page 状态

The receive calls normally return any data available up to the requested amount,

我会将其解释为“如果一个数据包已到达(正确、按顺序等),您将获得整个数据包的数据”。但不能保证。

另一方面Windows docs指出:

recv will return as much data as is currently available—up to the size of the buffer specified.

这听起来更像是保证。

但是请注意,只有在数据包被正确接收并且是下一个有序数据包(具有下一个预期序列号)的情况下才会返回数据。

(2) 现在,TCP 层处理完整的数据包。它实际上不可能进行交错或任何操作。以太网有一个校验和,除非数据包被完全接收,否则无法计算校验和。以太网校验和不正确的数据包应该被网卡过滤掉。 TCP 还有一个校验和,需要计算所有数据包数据。因此,如果网卡已将数据包传递给您 OS,那么数据应该可用。

(3) 我不认为你可以假设如果收到数据包,它会立即可用。网卡的一个非常常见的功能是 TCP 分段卸载,它重建部分流并导致网卡传递一个 TCP 数据包,该数据包是从多个 TCP 数据包重建的。还有其他方法可以减少中断的数量,这或多或少会导致多个数据包同时到达。所以,更有可能的情况是你可能会有一些延迟,然后一次从几个数据包中接收数据。

关键是,与您描述的相反的情况很可能会发生。但是,我仍然不会编写一个对一次有多少数据块可用做出任何假设的应用程序。这否定了流的概念。