非阻塞accept在连接突发时返回EAGAIN的异常问题咨询
非阻塞
accept异常行为:队列多连接仅首次成功,休眠后才可获取后续连接 执行非阻塞accept循环时发现异常行为:当队列中有多个连接请求时,仅首次accept尝试成功,后续所有尝试均返回EAGAIN;但在首次成功accept后休眠一段时间,即可成功获取后续连接。
最小复现示例
#include <errno.h> #include <stdio.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> int main() { // 127.0.0.1:4200 struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(4200); addr.sin_addr.s_addr = htonl((127 << 24) + 1); // create a non blocking socket, listening localhost 4200 port int listen_sock = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); bind(listen_sock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)); listen(listen_sock, 0); // make two non-blocking connection request to the above address int conn[2]; for (int i = 0; i < 2; ++i) { conn[i] = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); connect(conn[i], (struct sockaddr*)&addr, sizeof(struct sockaddr_in)); } // after 10 seconds, the two connections above have succeeded sleep(10); // now perform three `accept` attempt on the listening socket. // since there are two connections above, // the first two `accept` attempt should succeed, // and the third one should return `EAGAIN` accept(listen_sock, 0, 0); accept(listen_sock, 0, 0); accept(listen_sock, 0, 0); // but oops, only the first `accept` attempt succeed. // the second and third attempt both return `EAGAIN` // now sleep for 2 more second and do two more `accept` attempt sleep(2); accept(listen_sock, 0, 0); // this one succeed accept(listen_sock, 0, 0); // this one fail with `EAGAIN` as expected close(conn[0]); close(conn[1]); close(listen_sock); }
strace运行输出
socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_IP) = 3 bind(3, {sa_family=AF_INET, sin_port=htons(4200), sin_addr=inet_addr("127.0.0.1")}, 16) = 0 listen(3, 0) = 0 socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_IP) = 4 connect(4, {sa_family=AF_INET, sin_port=htons(4200), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress) socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_IP) = 5 connect(5, {sa_family=AF_INET, sin_port=htons(4200), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress) clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=10, tv_nsec=0}, 0x7ffd05a80610) = 0 accept(3, NULL, NULL) = 6 accept(3, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable) accept(3, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable) clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=2, tv_nsec=0}, 0x7ffd05a80610) = 0 accept(3, NULL, NULL) = 7 accept(3, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable) close(4) = 0 close(5) = 0 close(3) = 0
补充实验
- 若建立三个连接,分三轮调用
accept且中间休眠,前两轮accept均仅能接受一个连接,之后返回EAGAIN;但第三轮无论休眠多久,accept始终返回EAGAIN - 对三个连接套接字调用
getsockopt,未发现错误 - 通过向连接写入数据验证连接是否成功建立:
- 在首次
accept调用前,第一个连接可写入,写入第二个和第三个连接返回EAGAIN - 首次
accept调用后立即检查,三个连接均可写入 - 后续保持可写入状态
- 在首次
现咨询该异常现象的原因及解决办法。
内容的提问来源于stack exchange,提问作者Guest0x0
相关产品推荐
相关产品推荐

