我已经看到了一些关于讨论基础协议的send()
的问题。我完全清楚,对于TCP,任何消息都可能在发送时被分解成部分,并且无法保证接收器将在一次原子操作中获取消息。在这个问题中,我只谈论send()
系统调用的行为,因为它与本地系统的网络层交互。
根据POSIX标准和我读过的send()
文档,要发送的消息的长度由 length 参数指定。请注意:send()
发送一条长度长度的消息。进一步:
如果发送套接字上没有空间来保留消息 传输,并且套接字文件描述符没有
O_NONBLOCK
设置,send()
将阻止,直到空间可用。如果空间 发送套接字不能保存消息 传输,套接字文件描述符确实有O_NONBLOCK
设置,send()
将失败。
我认为send()的定义中没有任何可能返回-1
以外的任何值(这意味着没有数据在内核中排队等待传输)或 length ,这意味着整个消息在内核中排队等待传输。即,在我看来send()
必须是原子,关于本地排队消息以便在内核中传递。
send()
期间出现信号,则必须返回-1
。显然,在这种情况下我们不能排队部分消息,因为我们不知道发送了多少消息。因此在这种情况下无法发送任何内容。send()
必须阻塞,直到空间可用。然后邮件将排队,send()
返回 length 。send()
必须失败(返回-1
)和errno
将设置为EAGAIN
或EWOULDBLOCK
。同样,由于我们返回-1
,很明显在这种情况下,邮件的任何部分都不能排队。我错过了什么吗? send()是否可以返回>=0 && <length
的值?在什么情况下?那么非POSIX / UNIX系统呢? Windows send()
实现是否符合此标准?
答案 0 :(得分:10)
你的观点2过于简化了。 send
返回大于零但小于长度的值的正常条件(注意,正如其他人所说,除了长度参数为零之外它永远不能返回零)是消息足够长的时候导致阻塞,并且在已经发送一些内容之后到达中断信号。在这种情况下,send
EINTR
不会失败(因为这会阻止应用程序知道它已经成功发送了一些数据)并且它无法重新阻塞(因为信号正在中断,整个这一点是为了摆脱阻塞),所以它必须返回已发送的字节数,这小于请求的总长度。
答案 1 :(得分:4)
根据Posix规范和我30年来见过的所有 man 2发送页面,是的,send()
可以返回任何值&gt; 0和&lt; = length
。请注意,无法返回零。
根据几年前有关新闻的讨论:comp.protocols.tcp-ip所有TCP实现者所在的位置,阻塞send()
在转移所有数据之前不会实际返回到套接字发送缓冲区:换句话说,返回值是-1或length.
同意所有已知的实现都是如此,write(),
writev()
也是如此, sendmsg()
,writev()
,
答案 2 :(得分:3)
我知道这个东西在Linux上是如何工作的,使用GNU C Library。在这种情况下,您问题的第4点会有不同的描述。如果为文件描述符设置了标志O_NONBLOCK
,并且如果无法以原子方式将整个消息排入内核,send()
将返回实际发送的字节数(可以在1到1之间)长度),errno
设置为EWOULDBLOCK
。
(如果文件描述符在阻塞模式下工作,send()
将阻止。)
答案 3 :(得分:0)
澄清一点,它说:
将阻止,直到空间可用。
有几种方法可以从该区块/睡眠中醒来:
SO_SNDTIMEO
,超时到期。因此事情就这样结束了:
send()
可以被信号中断,发送超时可以过去,...导致短发送/部分写。如果没有将任何内容复制到发送缓冲区,则合理的实现将返回-1并将errno
设置为适当的值。 答案 4 :(得分:0)
在64位Linux系统上:
sendto(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4294967296, 0, NULL, 0) = 2147479552
因此,即使试图发送低4GB的内容,Linux也会发送出去并发送少于2GB的内容。因此,如果您认为自己会要求它发送1TB,并且它会耐心地坐在那里,那就继续祝愿。
类似地,在只有几个KB可用空间的嵌入式系统上,不要认为它会失败或等待某件事-它会发送尽可能多的信息,并告诉您有多少信息,让您可以重试其余步骤(或在此期间进行其他操作)。
每个人都同意,在使用EINTR的情况下,可能会发送短消息。但是EINTR可以随时发生,因此总会发送短消息。
最后,POSIX说返回的字节数是句点。正式的Unix和POSIX都建立在短读/写概念的基础上,它允许POSIX系统的实现从最小的嵌入式扩展到带有众所周知的“大数据”的超级计算机。因此,无需尝试在各行之间阅读并沉迷于手头上的特定即席实现。还有更多的实现方式,只要您遵循标准一词,您的应用就可以在其中移植。