TCP/UDP 和以太网 MTU 分片
Posted
技术标签:
【中文标题】TCP/UDP 和以太网 MTU 分片【英文标题】:TCP/UDP and ethernet MTU Fragmentation 【发布时间】:2011-01-25 07:58:46 【问题描述】:我已经在线阅读了各种网站和教程,但我仍然感到困惑。如果消息大于 IP MTU,则send()
返回发送的字节。消息的其余部分会发生什么?我是否要再次致电send()
并尝试发送其余消息?还是 IP 层应该自动处理的事情?
【问题讨论】:
【参考方案1】:如果您使用 TCP,那么呈现给您的接口就是字节流接口。您无需担心字节流如何从连接的一端到达另一端。您可以忽略 IP 层的 MTU。事实上,您可以完全忽略 IP 层。
当您调用send()
时,您计算机上的 TCP 堆栈将处理所有必要的细节,以便您推送到发送调用中的字节流从连接另一端的recv()
调用中出现。
要记住的一件事是,使用 TCP 您正在处理一个流,这意味着一个 send()
可能导致数据到达多个 recv()
调用,而多个 send()
调用可能导致数据到达一个单个recv()
电话。你无法控制这一点。您正在处理字节流,每次调用 recv()
都可以返回从 1 到当前未完成的字节数之间的任意字节数(允许将足够的缓冲区传递给 recv()
调用)。
因为评论者要求它;)
在大多数 TCP 堆栈上,send()
最有可能无法发送所有内容,因为 TCP 堆栈的缓冲区已满,并且(可能)TCP 窗口也已满并且流控制正在运行,这意味着堆栈无法发送任何更多数据,直到远程端确认一些数据并且它不准备代表您再缓冲。我还没有遇到一个 TCP 堆栈会因为 MTU 的考虑而拒绝 send()
,但我猜一些精简的嵌入式系统可能会这样......
无论如何,如果send()
返回的字节数少于您提供的字节数,那么您应该在某个时候重新发送剩余的数据。 send()
通常会阻塞并等待它可以发送所有数据,如果您已将套接字设置为非阻塞模式,那么如果它无法发送所有数据,您可能不想立即重试发送。可能会陷入一个紧密的循环......
更具体地了解您正在使用的操作系统可能对您有用。
【讨论】:
+1,但为了完成,您还应该处理问题最感兴趣的问题:如果send
返回的值小于要发送的请求字节(极不可能的情况,因为堆栈会尝试处理它)如果必须,您有责任稍后尝试发送其余数据。
真的不太可能吗?因为当请求的字节超过 MTU 时,send()
返回的值似乎小于要发送的请求字节。
c 中的 Unix。但是你已经详细地回答了我的问题。非常感谢!!【参考方案2】:
如果数据包太大而无法通过网络,则会发送 ICMP 分段提示,通知发送方减小数据包大小并重试。
如果您使用 TCP,这些都是您应该期望网络层为您处理的所有细节。现代 IP 堆栈实际上在幕后所做的以找出沿途最低 MTU 的做法似乎已成为某种黑色艺术。
WRT UDP 您仍然可以期望堆栈为您分段,但实际上考虑到 UDP 的用例并不理想。根据您的应用程序,您可能会通过明确了解路径 MTU 看到更好的性能。
... 在 send() 问题上,一些堆栈的行为不同,但处理 WRT 您的代码应该是相同的。假设您有 100 个字节要发送... send() 返回发送的 10 个字节。您需要使用剩余的 90 个字节继续调用 send,直到它全部推出来发送整个消息。
在 Windows 平台上使用阻塞套接字 send() 通常会在发送完所有内容后返回。在其他平台上。Linux 等您将需要更频繁地发送数据以推送数据。
【讨论】:
以上是关于TCP/UDP 和以太网 MTU 分片的主要内容,如果未能解决你的问题,请参考以下文章