非阻塞套接字的手册页中详细记录了两个案例:
非阻塞套接字未记录的内容是:
是否可以安全地假设send()甚至会在一个字节的数据上返回EAGAIN / EWOULDBLOCK?或者,非阻塞程序是否应该再次发送()以获得结论性的EAGAIN / EWOULDBLOCK?我担心在插座上放置一个EPOLLOUT观察器,如果它实际上没有处于“阻塞”状态以响应它的出现。
显然,后一种策略(再次尝试获得某种结论)具有明确定义的行为,但它更加冗长并且会对性能产生影响。
答案 0 :(得分:27)
致电send
有三种可能的结果:
send
成功并返回接受的字节数(可能比您要求的少)。send
时,发送缓冲区已完全
→如果套接字阻塞,send
阻止send
会因EWOULDBLOCK
/ EAGAIN
send
因其他错误而失败如果send
接受的字节数小于您要求的数量,那么这意味着发送缓冲区现在已满。但是,对于未来对send
的任何调用,这纯粹是间接的,非授权的
send
返回的信息仅仅是您调用send
时当前状态的“快照”。当send
返回时或再次拨打send
时,此信息可能已经过时。当您的程序在send
内,或者在纳秒之后,或者在任何其他时间,网卡可能会在线上放置数据报 - 无法知道。您将知道下一个呼叫何时成功(或何时不成功)。
换句话说,不暗示下一次调用send
将返回EWOULDBLOCK
/ EAGAIN
(或者如果套接字没有,则会阻止) t非阻塞)。尝试直到所谓的“获得结论EWOULDBLOCK
”是正确的事情。
答案 1 :(得分:4)
如果send()返回与传输缓冲区相同的长度,则整个传输成功完成,并且套接字可能处于阻塞状态,也可能不处于阻塞状态。
没有。套接字保持其所处的模式:在这种情况下,非阻塞模式,假设在下面。
如果send()返回-1并且errno是EAGAIN / EWOULDBLOCK,则没有传输完成,并且程序需要等到套接字不再阻塞。
直到发送缓冲区不再满。套接字保持非阻塞模式。
如果send()返回一个小于缓冲区大小的正值。
套接字发送缓冲区中只有那么多空间。
假设send()甚至会阻塞一个字节的数据是否安全?
“假设[它]会阻止”是不安全的。它不会。它处于非阻塞模式。 EWOULDBLOCK意味着将阻止阻止模式。
或者非阻塞程序是否应该再次发送()以获得最终的EAGAIN / EWOULDBLOCK?
这取决于你。 API适用于您决定的任何内容。
我担心在插座上放一个EPOLLOUT观察器,如果它实际上并没有阻塞它。
这不是'阻止'。它不会阻止任何事情。它处于非阻塞模式。发送缓冲区在那一刻被填满。片刻之后它可能完全是空的。
我不明白你在担心什么。如果您有待处理的数据,并且最后一次写入没有全部发送,请选择可写性,并在获得时写入。如果这样的写发送了所有内容,请不要在下次选择写入。
套接字通常是可写的,除非它们的发送缓冲区已满,所以不要一直选择可写性,因为你只需要一个旋转循环。