使用具有大量文件描述符的 select() 的外部代码

External code using select() with large numbers of file descriptors

我有一个用 C++ 编写的服务器程序,它在 Linux 上运行并使用 TCP 实现基于推送的消息服务。由于推送方法,可能有很多同时连接(我计划大约 100 万)必须保持打开更长时间。大多数情况下,这些连接处于空闲状态,偶尔会发出心跳,并且传输通常会同时在许多连接上突发。

为了让事情正常进行,我使用 epoll 来多路复用大量套接字,并且通过修改 RLIMIT_NOFILE,它确实适用于大量套接字。

我的问题是我还在同一个程序中使用其他类型的连接,最著名的是 FastCGI(使用 FastCGI SDK 中的 libfcgi)来接受 HTTP 请求,它们使用 select() 作为它们的内部文件描述符。当这些文件描述符变得大于 1024 (FD_SETSIZE) 时,这会导致问题,如果程序的 epoll 部分用完大部分低于 1024 的 fd 数字,这必然会发生。

我想知道处理这个问题的最佳方法是什么。

我是否只需要修改所有使用 select() 的外部代码并改用 poll()

有没有办法强制我基于 epoll 的代码(特别是 accept() 调用)仅使用 1024 以上的文件描述符,以便下面的那些保留给 select()基于代码?

我知道可以通过某种方式增加 FD_SETSIZE 的值,但我认为由于 select() 的工作方式,这会对性能造成很大影响,这让我印象深刻破解而不是真正的解决方案。

我建议将这些东西移到它们自己的进程中,以便它们获得自己的文件描述符。我建议你有一个协议,可以在单个 TCP 连接上多路复用大量 TCP 连接。您的服务器将与多路复用器而不是单个客户端通信。多路复用器可以 运行 在同一台机器或不同机器上,它可以处理数万个客户端连接,并且只会与服务器建立一个连接。

这样做的一大优势是您的服务器机器不必处理大量的 TCP 连接状态。它不必处理 Internet 垃圾,例如丢包、重传、重复包、流氓 SYN、慢速链接等。它不必为每个客户端都发送缓冲区,而只需要与可以为客户端进行缓冲的快速、干净的多路复用器通信。

如果工作量太大或由于某种原因无法完成,您可以使用 dup2 将文件描述符重新编号为更高编号的描述符。不过,我强烈建议使用多路复用器——您尝试处理的连接数量太大,无法从单个进程处理。