TCP/UDP和以太网MTU分段

3

我已经阅读了许多网站和在线教程,但仍然感到困惑。如果消息大于IP MTU,则send()返回发送的字节数。剩下的消息会发生什么?我需要再次调用send()并尝试发送剩余的消息吗?还是这是IP层应该自动处理的事情?

2个回答

6
如果您正在使用TCP,则呈现给您的接口是字节流。您不需要担心字节流如何从连接的一端传输到另一端。您可以忽略IP层的MTU。实际上,您可以完全忽略IP层。
当您调用send()时,您计算机上的TCP堆栈将处理所有必要的细节,使您通过发送调用推入的字节流从连接的另一端的recv()调用中出现。
唯一要记住的事情是,使用TCP时您正在处理流,这意味着一个send()可能会导致数据在多个recv()调用中到达,并且多个send()调用可能会导致数据在单个recv()调用中到达。您对此无法控制。您正在处理一系列字节,每次调用recv()都可以返回任何数量的字节,范围从1到当前未完成的数量(允许向recv()调用传递足够的缓冲区)。
由于评论者要求它 ;)
在大多数TCP堆栈上,send()最有可能无法发送所有内容,因为TCP堆栈的缓冲区已满,并且(可能)TCP窗口也已满,并且流控制正在运行,这意味着堆栈不能发送更多的数据,直到远程端ACK一些数据并且它不准备代表您缓冲更多数据。我从未遇到过由于MTU考虑而拒绝send()的TCP堆栈,但我想一些精简的嵌入式系统可能会有这种行为...
无论如何,如果send()返回的字节数少于您提供的字节数,则应在某个时间重新发送剩余的数据。通常,send()将阻塞并等待直到可以发送所有数据,并且如果您已将套接字设置为非阻塞模式,则可能不希望在发送失败时立即重试发送,因为您可能会陷入紧密的循环...
对于您使用的操作系统,更具体地说明将是有用的。

5
+1,但为了完整起见,您还应处理问题中最感兴趣的内容:如果send返回的值小于要发送的字节数(这是非常不可能发生的情况,因为堆栈会尝试处理它),则如果必须的话,您有责任稍后再尝试发送剩余的数据。 - David Rodríguez - dribeas
这真的不太可能吗?因为当请求字节数超过 MTU 时,我似乎总是会通过 send() 收到比请求发送的字节数更小的返回值。 - Fantastic Fourier
Unix 在 C 语言中。但是您已经详细地回答了我的问题。非常感谢! - Fantastic Fourier

0

如果数据包太大无法通过网络传输,则会发送ICMP分段提示,通知发送方减小数据包大小并重试。

如果使用TCP,这些都是你应该期望网络层为你处理的细节。现代IP堆栈实际上在幕后执行的操作,以确定路径上最低MTU似乎已经成为某种黑科技。

关于UDP,您仍然可以期望堆栈为您分段,但实际上,鉴于UDP的用例,这并不理想...根据您的应用程序,通过明确了解路径MTU,您可能会看到更好的性能。

关于send()问题,一些堆栈的行为不同,但WRT您的代码处理应该是相同的。假设您要发送100个字节... send()返回10个字节已发送。您需要继续使用剩余的90个字节调用send(),直到将整个消息推送到线路上为止。

在Windows平台上使用阻塞套接字,send()通常会在所有内容发送完毕后返回。在其他平台上,如Linux等,您需要更频繁地发送以推送数据。


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