使用 recv(n) 时,如果 n 大于 MTU,您能保证至少读取整个第 2 层帧吗?
Posted
技术标签:
【中文标题】使用 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? 【发布时间】:2022-01-15 15:57:08 【问题描述】:我想知道,假设如果没有数据可以从 TCP 套接字读取,那么一整帧 1492 字节会到达(满)。在您的代码(C 或任何支持 TCP 的语言)中,您可以说 recv 4096 字节,操作系统是否保证 recv 读取整个 1492 字节,或者内存中的帧加载和 recv 是否“交错” ,所以recv可能会变少?
【问题讨论】:
【参考方案1】:TCP 是一种面向流的协议。数据按顺序接收,但在收到所有数据之前,您不得假设必须调用 recv 多少次。 由您的应用程序重复对 recv 的调用,直到您知道自己已收到所需内容为止。
【讨论】:
【参考方案2】:(1) TCP 是面向流的协议。这意味着它在发送者上接受来自上层的数据流,并在接收者上将数据流返回给上层。 TCP 本身从 IP 层接收数据包,然后重构流。那就是在某些时候数据包不再存在。从理论上讲,在这个重构流的某个地方,可能只有一半传入的数据包被复制到缓冲区中,但在我看来这不太可能发生。
现在,linux man page 状态
接收调用通常会返回不超过请求数量的任何可用数据,
我会将其解释为“如果一个数据包已经到达(正确,按顺序等),您将获得整个数据包的数据”。但不能保证。
另一方面,Windows docs 表示:
recv 将返回当前可用的尽可能多的数据——最大为指定的缓冲区大小。
这听起来更像是保证。
但是请注意,只有当数据包被正确接收并且它是下一个有序数据包(具有下一个预期的序列号)时才会返回数据。
(2) 现在,TCP 层处理完整的数据包。它实际上不可能进行交错或任何事情。以太网有一个校验和,除非完全接收到数据包,否则无法计算该校验和。以太网校验和不正确的数据包应该被网卡过滤掉。 TCP 也有一个校验和,它需要计算所有的数据包数据。因此,如果网卡已将数据包传递给您的操作系统,那么数据应该是可用的。
(3) 我认为您不能假设如果收到数据包,它就立即可用。网卡的一个非常常见的特性是 TCP 分段卸载,它重构部分流并导致网卡通过一个 TCP 数据包,该数据包是从多个 TCP 数据包重构的。还可以采取其他措施来减少中断的数量,这或多或少会导致同时出现多个数据包。因此,更有可能的情况是您可能会有一些延迟,然后一次从多个数据包中接收数据。
关键是,与您描述的相反的情况很可能会发生。但是,我仍然不会编写一个应用程序来假设一次有多大的数据块可用。这否定了流的概念。
【讨论】:
以上是关于使用 recv(n) 时,如果 n 大于 MTU,您能保证至少读取整个第 2 层帧吗?的主要内容,如果未能解决你的问题,请参考以下文章
如果我发送的UDP数据包大小大于2个较小的MTU,会发生什么情况?