可以在TCP套接字上发送send()返回> = 0并且<length?

Mad*_*ist 20 c sockets tcp

我已经看到了一些关于send()它的问题,讨论了底层协议.我完全清楚,对于TCP,任何消息都可能在发送时被分解为部分,并且无法保证接收器将在一次原子操作中获取消息.在这个问题中,我只谈论send()系统调用的行为,因为它与本地系统的网络层交互.

根据POSIX标准和send()我读过的文档,要发送的消息的长度 length 参数指定.请注意:send()发送一条长度为length的消息.进一步:

如果发送套接字上没有空间来保存要传输的消息,并且套接字文件描述符没有 O_NONBLOCK设置,send()则应阻塞直到空间可用.如果发送套接字上没有空间来保存要传输的消息,并且套接字文件描述符确实已O_NONBLOCK设置,则将 send()失败.

我没有看到send()在这个定义中有任何可能返回除了-1(这意味着没有数据在内核中排队等待传输)或长度之外的任何值,这意味着整个消息在内核中排队等待传输.也就是说,在我看来,对于本地排队消息以便在内核中传递,send()必须是原子.

  1. 如果内核中的套接字队列中有足够的空间用于整个消息并且没有信号发生(正常情况),则将其复制并返回长度.
  2. 如果在期间发生信号send(),则必须返回-1.显然,在这种情况下我们不能排队部分消息,因为我们不知道发送了多少消息.因此在这种情况下无法发送任何内容.
  3. 如果内核中的套接字队列中没有足够的空间用于整个消息并且套接字阻塞,那么根据上面的语句send()必须阻塞,直到空间可用.然后消息将排队并send()返回长度.
  4. 如果内核中的套接字队列中没有足够的空间用于整个消息,并且套接字是非阻塞的,则send()必须失败(返回-1)并将errno设置为EAGAINEWOULDBLOCK.同样,因为我们返回-1它很清楚,在这种情况下,消息的任何部分都不能排队.

我错过了什么吗?send()是否可以返回一个值>=0 && <length?在什么情况下?那么非POSIX/UNIX系统呢?Windows send()实现是否符合此要求?

R..*_*R.. 10

你的观点2过于简化了.send返回大于零但小于length的值的正常条件(注意,正如其他人所说的那样,除了长度参数为零之外,它永远不会返回零)是消息足够长以导致阻塞,并且一些内容已经发送后,中断信号到达.在这种情况下,send不能失败EINTR(因为这会阻止应用程序知道它已经成功发送了一些数据)并且它无法重新阻塞(因为信号正在中断,并且整个过程就是没有阻塞) ,因此它必须返回已发送的字节数,这小于请求的总长度.


use*_*421 6

  1. 根据 Posix 规范和我 30 年来见过的所有man 2 send pages,是的,send()可以返回任何 > 0 和 <= 的值length。请注意,它不能返回零。

  2. 根据几年前关于 news:comp.protocols.tcp-ip 的讨论,所有 TCP 实现者都在那里,send()直到将所有数据传输到套接字发送缓冲区之前,阻塞实际上不会返回:换句话说,返回值是 -1 或length.一致认为这适用于所有已知的实现,也适用于write(), writev(), sendmsg(), writev(),

  • @MadScientist:如果在发送某些数据后信号中断传输,则 `errno` 是 **not** 设置(设置为 `EINTR` 或任何其他有意义的)。`EINTR` 错误条件仅适用于信号在*传输任何数据之前*操作中断的情况。在所有其他情况下,它不是“错误”,而只是“短发送”(短于全长)。 (4认同)
  • 对于#2,信号中断可能会触发短写返回值。 (2认同)