一尘不染

当非阻塞send()仅传输部分数据时,我们可以假定它在下一次调用时将返回EWOULDBLOCK吗?

linux

手册页中针对非阻塞套接字有两种情况的详细记录:

  • 如果send()返回的长度与传输缓冲区的长度相同, 则整个传输 成功完成,并且套接字可能会或可能不处于返回EAGAIN / EWOULDBLOCK的状态,以大于0字节的下一个调用进行传输。
  • 如果send()返回-1并且errno为EAGAIN / EWOULDBLOCK, 则传输没有 完成,程序需要等待套接字准备好接收更多数据(epoll情况下为EPOLLOUT)。

没有记录的非阻塞套接字是:

  • 如果send()返回的正值小于缓冲区大小。

是否可以安全地假设send()将对另外一个字节的数据返回EAGAIN /
EWOULDBLOCK?还是非阻塞程序应该尝试再发送一次send()以获得最终的EAGAIN /
EWOULDBLOCK?我担心如果EPOLLOUT监视程序实际上未处于“将要阻止”状态以响应该错误,则将它放在套接字上。

显然,后一种策略(再次尝试得出结论)具有明确的行为,但是它比较冗长,对性能造成了打击。


阅读 314

收藏
2020-06-07

共1个答案

一尘不染

呼叫send有三个可能的结果:

  1. 发送缓冲区中至少有一个字节可用→ send成功并返回接受的字节数(可能少于您要求的字节数)。
  2. 调用时,发送缓冲区已 完全满send
    →如果套接字正在阻塞,则send阻塞
    →如果套接字是非阻塞,则send失败并显示EWOULDBLOCK/EAGAIN

  3. 发生错误(例如,用户拉扯了网络电缆,对等方重置了连接)→ send失败并出现另一个错误

如果接受的字节数send小于您要求的字节数,那么这意味着发送缓冲区现在已完全填满。但是,这纯粹是间接的,对于以后的任何呼叫均不具权威性send
返回的信息send仅仅是您调用时当前状态的“快照”
send。在send返回的时间或您send再次致电时,此信息可能已过时。当您的程序在内部send,一纳秒后或在任何其他时间,网卡可能会将数据报放在线路上-
无法知道。您将知道下一次呼叫何时成功(或何时不成功)。

换句话说,但这 并不 意味着下一次调用send将返回EWOULDBLOCK/
EAGAIN(或者套接字未无阻塞会阻止)。尝试直到您所谓的“得到结论EWOULDBLOCK”才是正确的做法。

2020-06-07