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