在 C 中使用 epoll 和 EPOLLET 的多线程 TCP 侦听器
Multithreaded TCP listener with epoll and EPOLLET in C
我想用epoll和EPOLLET
写一个多线程的TCP监听器。
我看到有几种可能:
每个线程都有自己的 epoll fd,bind()
使用 SO_REUSEPORT
(但仅在 Linux 内核 3.9 以上)并处理自己的连接。 EPOLLONESHOT
在这种情况下不需要,因为每个线程处理自己的文件描述符。
有一个接受连接的主线程和几个处理这些连接的工作线程。每个工作线程都有自己的 epoll fd。在这种情况下,主线程如何在工作线程之间公平地分配连接?它可以使用循环方式将文件描述符添加到另一个线程的 epoll fd(但可能会发生该特定线程仍在忙于处理另一个连接)。或者可以将连接添加到全局队列,主线程将使用 pthread_cond_signal()
,但我们需要一个互斥锁和一个条件变量。
有一个接受连接的主线程和几个处理这些连接的工作线程。有一个全局 epoll fd,在这种情况下需要 EPOLLONESHOT
,因此并非所有线程都会为同一事件唤醒。
我知道,如果使用 EPOLLET
,一旦我收到事件通知,我必须耗尽 fd,直到我得到 EAGAIN
。
如果不支持套接字选项 SO_REUSEPORT
(较旧的内核),哪个选项最好?
- 1 的变体,但没有 SO_REUSEPORT 是共享侦听套接字。每个工作线程 运行 它自己的事件循环,除了处理自己的连接外,它们还在侦听套接字上执行非阻塞 accept() 。有关更详尽的描述,请参见例如http://aosabook.org/en/nginx.html
- 不使用
SO_REUSEPORT
的解决方案是拥有一个公共的 epoll fd 和一个在所有线程之间共享的公共侦听器。 EPOLLONESHOT
是必需的,因此一次只有一个线程处理特定 fd 的事件。
我想用epoll和EPOLLET
写一个多线程的TCP监听器。
我看到有几种可能:
每个线程都有自己的 epoll fd,
bind()
使用SO_REUSEPORT
(但仅在 Linux 内核 3.9 以上)并处理自己的连接。EPOLLONESHOT
在这种情况下不需要,因为每个线程处理自己的文件描述符。有一个接受连接的主线程和几个处理这些连接的工作线程。每个工作线程都有自己的 epoll fd。在这种情况下,主线程如何在工作线程之间公平地分配连接?它可以使用循环方式将文件描述符添加到另一个线程的 epoll fd(但可能会发生该特定线程仍在忙于处理另一个连接)。或者可以将连接添加到全局队列,主线程将使用
pthread_cond_signal()
,但我们需要一个互斥锁和一个条件变量。有一个接受连接的主线程和几个处理这些连接的工作线程。有一个全局 epoll fd,在这种情况下需要
EPOLLONESHOT
,因此并非所有线程都会为同一事件唤醒。
我知道,如果使用 EPOLLET
,一旦我收到事件通知,我必须耗尽 fd,直到我得到 EAGAIN
。
如果不支持套接字选项 SO_REUSEPORT
(较旧的内核),哪个选项最好?
- 1 的变体,但没有 SO_REUSEPORT 是共享侦听套接字。每个工作线程 运行 它自己的事件循环,除了处理自己的连接外,它们还在侦听套接字上执行非阻塞 accept() 。有关更详尽的描述,请参见例如http://aosabook.org/en/nginx.html
- 不使用
SO_REUSEPORT
的解决方案是拥有一个公共的 epoll fd 和一个在所有线程之间共享的公共侦听器。EPOLLONESHOT
是必需的,因此一次只有一个线程处理特定 fd 的事件。