EPOLL

支持者

 

TsgcWebSocketServer

TsgcWebSocketHTTPServer

 

*需要 sgcWebSockets Enterprise Edition。

 

Linux 的 EPOLL 是一种 API,允许使用有限的线程池处理数千个连接,而非像 Indy 默认的每连接一个线程方式。

要为 Indy 服务器启用 EPOLL,请转至 IOHandlerOptions 属性,然后选择 iohIEPOLL 作为 IOHandler 类型。


Server.IOHandlerOptions.IOHandlerType := iohEPOLL;
Server.IOHandlerOptions.EPOLL.EPOLLThreads := 0;
Server.IOHandlerOptions.EPOLL.WorkOpThreads := 0;
Server.IOHandlerOptions.EPOLL.PartialRequestTimeout := 0;
Server.IOHandlerOptions.EPOLL.TCPKeepAlive.Enabled := True;
Server.IOHandlerOptions.KeepAliveTimeout := 120;

 

EPOLLThreads 是用于 EPOLL 异步请求(重叠操作)的线程数,默认值为零,表示线程数根据处理器数量计算(Delphi 7 和 2007 除外,在这些版本中线程数设置为 32,因为不支持 cpucount 函数)。您可以手动调整线程数。

WorkOpThreads 用于设置为处理请求而保持就绪的工作线程的最小数量,默认值为 0。EPOLL 线程只负责检测套接字是否就绪,并把实际工作交给这个线程池,因此绝不会被速度缓慢的客户端阻塞。当所有工作线程都已在忙碌时,该线程池会按需增长,直至达到固定的上限,因此无需事先规划它的大小。只有当您希望在第一个请求到达之前线程池就已准备就绪时,才需要调大这个值,这样可以避免在连接集中涌入的初期支付线程创建的开销。

2026.9.0 中的变更。 以前 WorkOpThreads 会把每个连接固定到其中一个线程上,因此同一连接上的所有请求都在同一线程中运行,而 WorkOpRoundRobin 则决定新连接如何分配到这些线程上。这种固定绑定已被移除,因为一个正在等待请求剩余部分而停住的连接会阻塞分配到同一线程上的其他所有连接,从而导致服务器停滞。现在同一连接上的请求可以在不同线程中运行,因此不能再假定按线程保存的内容(例如数据库连接或线程本地缓存)会跟随某个连接。WorkOpRoundRobin 已不复存在。请将它从代码中删除。如果您曾在 Object Inspector 中启用过它,还需要从窗体的 .dfm 中删除 WorkOpRoundRobin 那一行,否则窗体将无法加载。

PartialRequestTimeout 用于让服务器等待接收长度已知的 HTTP 请求正文的剩余部分到达,单位为毫秒,默认值为 0,表示禁用此功能。如果未启用此选项,当请求正文未能在单次就绪事件内全部到达时(例如一个大的 POST 请求被拆分为多个数据包发送),该请求会被静默丢弃,连接也会在不作任何响应的情况下关闭。这个等待过程不会运行在需要服务大量连接、绝不能被阻塞的 EPOLL 线程上,而是运行在上文所述的工作线程池中,该线程池会按需增长,直至达到固定的上限,因此速度缓慢或无响应的客户端不会耗尽该线程池,也不会因此拖累其他连接。

TCPKeepAlive 允许操作系统探测空闲连接,检测已悄然消失的对端(默认禁用)。当 TCPKeepAlive.Enabled 设置为 True 时,操作系统会在连接空闲达到 TCPKeepAlive.Time 秒(默认 60 秒)后开始探测该连接,此后每隔 TCPKeepAlive.Interval 秒(默认 10 秒)重复探测一次,直到对端响应或连接被断开为止。

KeepAliveTimeout 会关闭空闲时间超过指定秒数的任何连接(默认值为 0,表示禁用)。此超时仅影响空闲连接,正在读取的请求或正在写入的响应不会被此超时中断。这与默认的每连接一线程 IOHandler 释放静默连接的方式最为接近,并且不依赖操作系统,也不需要对端的任何配合。

 

当您需要处理数千个连接时,建议为 Linux 服务器启用 EPOLL。如果您的服务器最多只处理 100 个并发连接,则可以继续使用默认的 Indy 线程模型。

 

 

OnDisconnect 事件未触发

 

EPOLL 与默认的 Indy IOHandler 工作方式不同。使用默认 Indy IOHandler 时,每个连接都在一个线程中运行,这些线程持续运行并检查连接是否活跃,因此如果发生断连,会在较短时间内收到通知。

 

EPOLL 的工作方式与默认的 Indy(1 个线程对应 1 个连接)不同,它使用线程池来处理所有连接。对于 EPOLL,检测连接是否仍然存活的唯一方法是尝试向套接字写入数据,如果出现任何错误,则表示连接已关闭。有三种方式可以检测断线:

 

1. 如果使用 TsgcWebSocketClient,可以在 Options 属性中启用它,CleanDisconnect := True(默认禁用)。启用后,客户端断开连接之前会发送一条通知服务器断开的消息,服务器将收到此消息并触发 OnDisconnect 事件。

2. 您可以在服务器端启用心跳,例如每 60 秒向所有已连接的客户端发送一次 ping,若有客户端断开,则调用 OnDisconnect。

3. 您可以在服务器的 IOHandlerOptions 上启用 TCPKeepAlive 和/或设置 KeepAliveTimeout。这样服务器就能自行检测到已静默的对端(例如客户端崩溃,或网络连接中断而未发送关闭消息),并关闭该连接,而无需依赖客户端发送任何数据。

 

Linux 连接限制

 

若要增加并发打开的连接数,请使用以下命令

 

ulimit -n 10000

 

上一条命令将打开文件描述符的最大数量设置为 10000