3

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

4

4 回答 4

1

这以前出现过。我仍在寻找参考答案。

让我们从 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 会返回一个完整的缓冲区。

于 2013-04-23T09:25:48.953 回答
0

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

于 2013-04-23T09:11:15.217 回答
0

来自官方 POSIX 参考

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

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

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

于 2013-04-23T09:01:04.527 回答
0

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

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

升级版:

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

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

于 2013-04-23T09:04:38.587 回答