c - 向轮询监听套接字的 epoll 实例以外的 epoll 实例添加新套接字

标签 c linux sockets file-descriptor epoll

情况:

  • 多个进程共享同一个文件描述符表。
  • 每个进程监听自己的 epoll 实例。
  • 所有套接字和涉及它们的调用都是非阻塞的。
  • 在这些进程中,只有进程A将监听套接字添加到它的epoll实例。
  • 进程 A 知道所有其他进程的 epolls 的 fds。
  • 当新套接字(即新连接)到达时,进程 A 将其添加到其他进程之一的 epoll 实例中...

...像这样:

int new_sfd;
while ((new_sfd = accept4(listening_fd, NULL, NULL, SOCK_NONBLOCK)) != -1) {
    if (epoll_ctl(other_epoll_fds[new_sfd % PROCESS_C], EPOLL_CTL_ADD, new_sfd,
                  &(struct epoll_event){
                      .data = {.fd = new_sfd},
                      .events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET
                  }) == -1) {
        perror("Failed to add a new socket to an epoll instance");
        close(new_sfd);
    }
}
if (errno != EAGAIN) {
    perror("Failed to accept one or more incoming connections");
}

这似乎可行(即在此阶段没有发生错误)。当一个连接在进程 A 进入时,它被添加到进程 B 的 epoll 中,之后进程 B 得到一个设置了 EPOLLIN 标志的事件,如预期的那样。进程 B 然后通过读取接收到的 epoll_event 结构的 data.fd 成员获得新套接字的 fd,并尝试对该 fd 执行 recv()

这里的事情出乎意料地出错了。 recv() 返回 -1 并出现以下错误:非套接字上的套接字操作

什么给了?通过在各处插入大量调试printf()语句,我彻底验证了进程A中accept4()返回的fd值实际上与我在进程 B 中作为第一个参数传递给 recv() 的 fd 值(同样,所有进程共享同一个文件描述符表),所以我无法理解这一点。帮助?! D:

最佳答案

后来谷歌搜索了很多,我已经登陆了以下页面:

https://patchwork.kernel.org/patch/2356101/

显然 execve() 撤消了我使用 clone()CLONE_FILES 标志设置的文件描述符表的共享(因此调用 execve() 之后出现的任何套接字 fd 都会导致监听进程 A 的表写入时复制,从而使其他进程看不到更改。

我只是很不幸 execve() 的这种行为还没有记录在当前版本的手册中。因此 Kevin Easton 的上述补丁(感谢 Kevin)。另外,谢谢 Devolus引导我朝着正确的方向前进。

关于c - 向轮询监听套接字的 epoll 实例以外的 epoll 实例添加新套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16909856/

相关文章:

C代码问题..任何人都可以帮忙吗?

linux - 如何在linux中编写和加载GUI?

Python 套接字,高级聊天框

c - C语言中如何与父子进程共享内存

c++ - 套接字错误无法在 WinSock2.h 中获取函数

Java TCP/IP 服务器不正确地关闭连接

c - C语言中如何读取一组字符?

c - 使用 TRIES 实现 t9 字典

c++ - 非阻塞 recv 在断开连接时返回 0

php - 托管在 Linux 服务器上的文件需要什么文件权限?