使用具有大量文件描述符的 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
将文件描述符重新编号为更高编号的描述符。不过,我强烈建议使用多路复用器——您尝试处理的连接数量太大,无法从单个进程处理。
我有一个用 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
将文件描述符重新编号为更高编号的描述符。不过,我强烈建议使用多路复用器——您尝试处理的连接数量太大,无法从单个进程处理。