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