单次调用send()函数(TCP套接字)保证发送的最小数据大小是多少?

3

在使用select函数后,当写fd已设置为tcp socket时,如果我尝试在该socket上发送数据,使用send api发送的最小保证数据大小是多少?我知道我必须运行一个循环以确保所有数据都被发送。但我仍然想了解最小保证数据发送量和原因。


1
你为什么期望有一个最小保证大小呢? - Anish Ramaswamy
@AnishRam 因为TCP(对于IPv4兼容节点)的MSS为536。我期望如果我用数据大小小于536调用send,它不应该导致部分发送。 - CCoder
嗯,部分发送是否等同于数据被分成多个段? - Anish Ramaswamy
你不能指望那样。例如,Nagle算法可能会将一些或所有数据附加到先前的段上。在TCP中,您不能对分段和封包做出任何假设。 - user207421
4个回答

1
这个问题以前就出现过。我仍在寻找被引用的答案。
让我们从send()的函数原型开始。
对于阻塞TCP套接字 - 所有文档都会建议send()和write()返回一个值在[1..len]之间,除非出错。但是,事实上,我认识的人从未观察到send()返回除了-1(错误)或“len”(成功情况下表示发送了整个“buf”)之外的其他任何值。我从来没有对此感到满意,所以我保守地编写代码,只要通过循环才将整个缓冲区发送。
对于非阻塞TCP套接字 - 你应该假设最小值为“1”(或错误为-1)。不要做出数据大小的任何假设。
对于recv(),你应该始终假设在成功的情况下recv()将返回1..len之间的一些随机值,或0(关闭),或-1(错误)。永远不要假设recv会返回完整的缓冲区。

我会在我的回答中加入一些其他的讨论:https://dev59.com/KXE85IYBdhLWcg3wx2j2 - selbie
我完全同意,我也明白我应该在循环中调用send。我很好奇保证的大小以及限制的原因。我的理解是节点的MTU大小限制了一次发送调用中发送数据的大小。 - CCoder
不,MTU只影响内核将在适配器上发送多少数据。但这通常不会影响发送调用本身。对于大缓冲区的阻塞发送(send()),可能会生成许多数据包和TCP帧。 - selbie
这是我正在搜索的原始问题:https://dev59.com/SG7Xa4cB1Zd3GeqPlhP2 - selbie
在现代网络硬件/软件的世界中,即使要到达附近的个人电脑,您的数据包也要经过诸如WiFi路由器/防火墙MTU之类的东西,除非您正在构建非常特定的网络配置,否则您的“源”机器的MTU实际上没有那么重要。这可以被视为“愿望”而不是“指示”。 - evilruff

0

来自官方POSIX参考文献

当使用O_NONBLOCK清除调用输出函数时,描述符将被视为准备好写入,无论函数是否成功传输数据。

正如您所看到的,它实际上并没有提到任何大小,或者写入是否成功,只是说您可以在不阻塞的情况下写入套接字。

因此,答案是没有最小保证大小。


0

我认为在POSIX层上,你无法对此进行任何控制。send()将接受你传递到TCP/IP堆栈实现的内部缓冲区中的任何内容。接下来会发生什么,你可以使用相同的select()调用来监视。

如果你问的是一个数据包可以容纳多大的大小,那就是MTU(但这个假设也应该小心谨慎地使用,因为涉及到分片和重组数据包的问题)。

更新:

我会在这里回答你的评论。不,你不应该担心分片。把它留给TCP/IP堆栈处理。有很多理由你不应该这样做。例如,你的应用程序工作在OSI模型的应用层(虽然我认为OSI模型在大多数情况下都是一件坏事,但它确实适用于这个例子)。从这个层面上,你试图影响位于更低层的逻辑功能/属性(会话/传输)。你不应该这样做。像send()、recv()这样的POSIX调用旨在为你的应用程序提供指示底层层次传递一定量的数据的能力,并且你有一种监视命令执行的方法(select()),这就是你需要做的全部。更低层次的处理应该根据操作系统网络设置等,尽最大努力以最优化的方式传递你指示它们传递的数据。

更新2:以上大部分内容主要考虑非阻塞套接字。很抱歉忘了提到这一点,我已经很久没有在我的项目中使用阻塞套接字了。如果您的套接字是阻塞的,我仍然会考虑一次性传递所有内容,然后在另一个线程中等待操作结果,因为尝试优化这个可能会导致非常依赖于操作系统/驱动程序的代码。


我就是从那个点开始的。我的理解是,如果路径中所有节点的 MTU 大小 > 576,则在 IPv4 的情况下不需要分段。因此,我难道不能在单个发送调用中发送 < MSS 的数据吗? - CCoder
我已经更新了一个答案。 - evilruff

0

select() 指示 一个套接字可写时,保证您可以传输至少一个字节而不会遇到EWOULDBLOCKEAGAIN的错误。但是,并不意味着您不会遇到其他错误 :-)


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