在一次 send() 调用(tcp 套接字)中保证发送的最小数据大小是多少? [复制]

Posted

技术标签:

【中文标题】在一次 send() 调用(tcp 套接字)中保证发送的最小数据大小是多少? [复制]【英文标题】:What is the minimum size of data guaranteed to be sent in a single call of send() (tcp sockets)? [duplicate] 【发布时间】:2013-04-16 09:55:22 【问题描述】:

select 返回后,为 tcp 套接字设置了 write fd。如果我尝试在该套接字上发送数据,使用send api 一次发送数据的最小保证大小是多少?我知道我必须运行一个循环以确保发送所有数据。我仍然想了解发送的最低保证数据是多少以及为什么?

【问题讨论】:

您为什么希望有一个最小保证尺寸? @AnishRam 因为 TCP 的 MSS 为 536(适用于 IPv4 兼容节点)。而且我希望如果我用数据大小 嗯,部分发送是否等同于说数据被分割成段? 你不能指望那样。例如,部分或全部数据可能会被 Nagle 算法捎带到先前的段上。您不能对 TCP 中的分段和打包做出任何假设。 【参考方案1】:

来自the official POSIX reference:

当使用O_NONBLOCK clear 调用输出函数不会阻塞时,无论该函数是否会成功传输数据,都应认为描述符已准备好写入。

如您所见,它实际上并没有提及任何大小,或者写入甚至会成功,只是您可以在不阻塞的情况下写入套接字。

所以答案是没有最小保证尺寸。

【讨论】:

【参考方案2】:

我不认为在 POSIX 层上你可以控制它。 send() 将接受您传递到 TCP/IP 堆栈实现的内部缓冲区的任何内容。接下来会发生什么,这已经是另一个故事了,您可以使用相同的 select() 调用来查看它。

如果您询问适合 MTU 的一个数据包的大小(但在途中数据包的分段和重组方面也应谨慎使用此假设)

更新:

我会在这里回答你的评论。不,您根本不应该为碎片而烦恼。将其留给 TCP/IP 堆栈。您不应该这样做的原因有很多。举个例子。您的应用程序在 OSI 模型的 Application(7) 层上运行(虽然我认为 OSI 模型在大多数情况下是一个邪恶的东西,但它确实适用于这个示例)。从这一层开始,您试图影响位于低得多的层(会话/传输)上的逻辑的功能/属性。你不应该这样做。诸如 send()、recv() 之类的 POSIX 调用旨在让您的应用程序能够指示底层您需要传递一定数量的数据,并且您可以监控命令的执行 (select()),即所有你必须做的。并且较低层会尽力根据操作系统网络设置/等以最佳方式交付您指示他们执行的数据。

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

【讨论】:

我正是从那个时候开始的。我的理解是,如果路径中所有节点的 MTU 大小 > 576,那么在 IPv4 的情况下您不需要分段。那么我应该不能在单个发送调用中发送数据 我已经更新了答案【参考方案3】:

select() indicates 表明套接字是可写的时,保证您可以传输至少一个字节而不会产生EWOULDBLOCKEAGAIN。没什么可说的,但你不会产生不同的错误 :-)

【讨论】:

【参考方案4】:

这已经出现过。我仍在寻找参考答案。

让我们从 send() 的函数原型开始

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

对于阻塞 TCP 套接字 - 所有文档都会建议 send() 和 write() 将返回 [1..len] 之间的值,除非出现错误。然而,现实情况是,我认识的任何人都没有观察到 send() 返回的东西不是 -1(错误)或成功案例中的“len”,以表明所有“buf”都是在一次调用中发送的。我从来没有对此感觉良好,所以我进行了防御性编码,只是将阻塞的发送调用置于循环中,直到发送整个缓冲区。

对于非阻塞 TCP 套接字 - 您应该将最小值设置为“1”(或错误时为 -1)。不要对最小数据大小做任何假设。

对于recv(),您应该始终假设recv() 将在成功情况下返回1..len 之间的随机值,或者0(关闭)或-1(错误)。永远不要假设 recv 会返回一个完整的缓冲区。

【讨论】:

我将通过其他讨论来补充我的答案:***.com/questions/2618736/… 我完全同意,我也明白我应该循环调用发送。我很想知道保证的大小以及限制的原因。我的理解是节点的 MTU 大小限制了一次发送调用中发送的数据大小。 不,MTU 只是影响内核将通过适配器发送多少。但这通常不会影响发送调用本身。大缓冲区的阻塞 send() 可能会转换为生成许多数据包和 TCP 帧。 这是我正在寻找的原始问题:***.com/questions/14700906/… 在网络硬件/软件的现代世界中,即使通过 PC 到达附近,您的数据包也会传递诸如“源”机器的 wifi 路由器/防火墙 MTU 之类的东西,根本没有那么大的意义,直到您构建非常具体的网络配置。这可以被视为“愿望”而不是“指示”

以上是关于在一次 send() 调用(tcp 套接字)中保证发送的最小数据大小是多少? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能激发 TCP 将 send() 拆分为多个 recv()

Linux:在 TCP 套接字上发送整个消息或不发送任何消息

C++ linux套接字,在一次调用中将字符串数组(char**)作为连接字符串发送

在c ++中使用multipe recv()和send()调用

TCP阻塞模型下服务器和客户端的建立步骤

当 TCP 连接中的链接断开时的 send() 函数行为