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

标签 c linux sockets nonblocking

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

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

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

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

假设 send() 会在多一个字节的数据上返回 EAGAIN/EWOULDBLOCK 是否安全?或者非阻塞程序是否应该尝试再发送一次 () 以获得最终的 EAGAIN/EWOULDBLOCK?如果套接字实际上不处于“会阻止”状态以响应它的出现,我担心将 EPOLLOUT 观察器放在套接字上。

显然,后一种策略(再次尝试获得结论)具有明确定义的行为,但它更加冗长并且会影响性​​能。

最佳答案

调用 send具有三种可能的结果:

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

如果 send 接受的字节数小于您要求的数量,那么这意味着发送缓冲区现在已满。然而,对于任何 future 对 send 的调用,这纯粹是间接的,并且是非权威的。
send 返回的信息只是您调用 send 时当前状态的“快照”。当 send 返回或您再次调用 send 时,此信息可能已经过时。当您的程序在 send 中时,网卡可能会在网络上发送数据报,或者在一纳秒之后,或者在任何其他时间——没有办法知道。您会知道下一次调用何时成功(或何时失败)。

换句话说,这暗示下一次调用send会返回EWOULDBLOCK/EAGAIN (或者如果套接字不是非阻塞的会阻塞)。尝试直到您所谓的“获得决定性的 EWOULDBLOCK”是正确的做法。

关于c - 当非阻塞 send() 仅传输部分数据时,我们可以假设它会在下一次调用时返回 EWOULDBLOCK 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19391208/

相关文章:

c - C 中的字节顺序和套接字编程

java - 从 java : Why doesn't the array get printed? 传递的 c 中打印数组

c# - 用 C# dll 替换 c api dll 而不影响客户端

c - 这在 C/C++ 套接字通信中是否合理?

linux - 查找最后几行中有空格的所有文件

c - 如何在 Windows/Linux C 上查看 CPU 名称、型号、速度?

PHP scandir() 在 cifs 挂载上失败,直到 php-fpm 重新启动

Char 与 unsigned char 转换为 int

java - 使用 Java 将 SOAP 消息格式转换为 Socket 消息格式,反之亦然

javascript - 在node.js中使用socket.io和express在用户登录时显示连接消息