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

有两种情况在非阻塞套接字的手册页中有详细logging:

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

没有logging的非阻塞套接字是:

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

假设send()会在甚至多一个字节的数据上返回EAGAIN / EWOULDBLOCK是否安全? 还是应该一个非阻塞的程序试图发送()一个更多的时间来得到一个决定性的EAGAIN / EWOULDBLOCK? 如果实际上并没有处于“阻塞”状态来响应它,我担心将EPOLLOUT监视器放在套接字上。

很显然,后一种策略(试图再次得出结论)具有明确定义的行为,但是更为冗长,并且对性能造成了冲击。

Solutions Collecting From Web of "当一个非阻塞send()只传输部分数据时,我们可以假设它会在下次调用时返回EWOULDBLOCK吗?"

send电话有三种可能的结果:

  1. 发送缓冲区中至少有一个字节可用→ send成功并返回接受的字节数(可能少于您要求的字节数)。
  2. 发送缓冲区在您呼叫send已满
    →如果套接字阻塞, send
    →如果套接字是非阻塞的,则使用EWOULDBLOCK / EAGAIN send失败
  3. 发生错误(例如,用户拔掉网线,连接被对方​​重置)→ send失败,并发生另一个错误

如果send接受的字节数小于请求的数量,则这意味着发送缓冲区现在已经完全满了。 但是,对于未来的电话send ,这纯粹是环境和非批准的。
通过send返回的信息仅仅是在您send时的当前状态的“快照”。 在send已经返回的时间或您再次呼叫send的时间之前,该信息可能已经过时。 网卡可能会在你的程序send ,或者在一个毫微秒之后,或者在任何其他时间,把数据报放在线路上 – 这是无法知道的。 你会知道什么时候下一个电话成功(或者什么时候没有)。

换句话说,这并不意味着下一个send调用将返回EWOULDBLOCK / EAGAIN (或者如果套接字不是非阻塞的话,将会阻塞)。 尝试,直到你所谓的“得到一个决定性的EWOULDBLOCK ”是正确的事情。

如果send()返回与传输缓冲区相同的长度,则整个传输成功完成,并且套接字可能处于阻塞状态,也可能不处于阻塞状态。

不是。插座保持在它所处的模式:在这种情况下,非阻塞模式,在下面被假设。

如果send()返回-1,而errno是EAGAIN / EWOULDBLOCK,则没有任何传输完成,程序需要等待,直到套接字不再被阻塞。

直到发送缓冲区不再满了。 套接字保持非阻塞模式。

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

在套接字发送缓冲区中只有这么多的空间。

假设send()会封锁一个字节的数据是否安全?

“假设它会阻止”是不安全的。 它不会。 它处于非阻塞模式。 EWOULDBLOCK意味着它将在阻塞模式下阻塞。

还是应该一个非阻塞的程序试图发送()一个更多的时间来得到一个决定性的EAGAIN / EWOULDBLOCK?

这取决于你。 API可以根据您的决定进行操作。

我很担心在插座上放一个EPOLLOUT监视器,如果它实际上没有阻塞的话。

这不是“阻碍”。 它不阻塞任何东西。 它处于非阻塞模式。 发送缓冲区在那个瞬间被填满了。 稍后可能完全空了。

我不明白你在担心什么 如果您有待处理的数据,并且最后一次写入没有发送完毕,请选择可写入性,并在获取时写入。 如果这样的写入发送一切,下次不要选择可写入。

套接字通常是可写的,除非它们的发送缓冲区已满,所以不要一直选择可写性,因为你只需要一个旋转循环。