在 C 中使用 epoll 和 EPOLLET 的多线程 TCP 侦听器

Multithreaded TCP listener with epoll and EPOLLET in C

我想用epoll和EPOLLET写一个多线程的TCP监听器。

我看到有几种可能:

  1. 每个线程都有自己的 epoll fd,bind() 使用 SO_REUSEPORT(但仅在 Linux 内核 3.9 以上)并处理自己的连接。 EPOLLONESHOT 在这种情况下不需要,因为每个线程处理自己的文件描述符。

  2. 有一个接受连接的主线程和几个处理这些连接的工作线程。每个工作线程都有自己的 epoll fd。在这种情况下,主线程如何在工作线程之间公平地分配连接?它可以使用循环方式将文件描述符添加到另一个线程的 epoll fd(但可能会发生该特定线程仍在忙于处理另一个连接)。或者可以将连接添加到全局队列,主线程将使用 pthread_cond_signal(),但我们需要一个互斥锁和一个条件变量。

  3. 有一个接受连接的主线程和几个处理这些连接的工作线程。有一个全局 epoll fd,在这种情况下需要 EPOLLONESHOT,因此并非所有线程都会为同一事件唤醒。

我知道,如果使用 EPOLLET,一旦我收到事件通知,我必须耗尽 fd,直到我得到 EAGAIN

如果不支持套接字选项 SO_REUSEPORT(较旧的内核),哪个选项最好?

  1. 1 的变体,但没有 SO_REUSEPORT 是共享侦听套接字。每个工作线程 运行 它自己的事件循环,除了处理自己的连接外,它们还在侦听套接字上执行非阻塞 accept() 。有关更详尽的描述,请参见例如http://aosabook.org/en/nginx.html
  1. 不使用 SO_REUSEPORT 的解决方案是拥有一个公共的 epoll fd 和一个在所有线程之间共享的公共侦听器。 EPOLLONESHOT 是必需的,因此一次只有一个线程处理特定 fd 的事件。