IOCP

Supported by

 

  TsgcWebSocketServer

  TsgcWebSocketHTTPServer

 

*Requires custom Indy version.

 

IOCP for Windows is an API that allows handling thousands of connections using a limited pool of threads instead of using one thread per connection as Indy does by default.

To enable IOCP for Indy Servers, Go to IOHandlerOptions property and select iohIOCP as IOHandler Type.


Server.IOHandlerOptions.IOHandlerType := iohIOCP;
Server.IOHandlerOptions.IOCP.IOCPThreads := 0;
Server.IOHandlerOptions.IOCP.WorkOpThreads := 0;
Server.IOHandlerOptions.IOCP.PartialRequestTimeout := 0;
Server.IOHandlerOptions.IOCP.TCPKeepAlive.Enabled := True;
Server.IOHandlerOptions.KeepAliveTimeout := 120;

 

IOCPThreads are the threads used for IOCP asynchronous requests (overlapped operations), by default the value is zero which means the number of threads are calculated using the number of processors (except for Delphi 7 and 2007 where the number of threads is set to 32 because the function cpucount is not supported).

WorkOpThreads sets the minimum number of worker threads kept ready to process requests, 0 by default. An IOCP thread only picks up a completed operation and hands the work to this pool, so it never blocks on a slow client. The pool grows on demand up to a fixed maximum whenever every worker is already busy, so it does not need to be sized in advance. Raise this value only if you want the pool already warm before the first request, which avoids paying for thread creation during an initial burst of connections.

Changed in 2026.9.0. WorkOpThreads used to pin every connection to one of these threads, so all requests on a connection ran on the same thread, and WorkOpRoundRobin chose how new connections were distributed over them. Pinning has been removed: a connection parked waiting for the rest of a request blocked every other connection assigned to the same thread, which stalled the server. Requests on the same connection can now run on different threads, so anything held per thread, such as a database connection or a thread-local cache, must no longer be assumed to follow a connection. WorkOpRoundRobin no longer exists. Remove it from your code, and if you enabled it in the Object Inspector, delete the WorkOpRoundRobin line from the form's .dfm as well, otherwise the form does not load.

PartialRequestTimeout lets the server wait for the rest of an HTTP request body whose length it already knows, in milliseconds and 0 by default, which disables it. Without it, a request body that does not all arrive within a single completion, for example a large POST sent in several packets, is silently dropped and the connection closed with no reply. The wait never runs on an IOCP thread, which services many connections and must never block, it runs on the worker pool described above, which grows on demand up to a fixed maximum, so a slow or unresponsive client cannot exhaust it and hold back the other connections.

TCPKeepAlive lets the operating system probe idle connections and detect a peer that has silently disappeared (disabled by default). When TCPKeepAlive.Enabled is set to True, the O/S starts probing a connection after it has been idle for TCPKeepAlive.Time seconds (60 by default), repeating every TCPKeepAlive.Interval seconds (10 by default) until the peer answers or the connection is dropped.

KeepAliveTimeout closes any connection that has been idle for longer than the given number of seconds (0 by default, which means disabled). Only idle connections are affected, a request that is being read or a response that is being written is never interrupted by this timeout. This is the closest match to how the default thread-per-connection IOHandler frees a silent connection, and it does not depend on the operating system or on any cooperation from the peer.

 

Enabling IOCP for windows servers is recommended when you need to handle thousands of connections. If your server is only handling a maximum of 100 concurrent connections, you can stay with the default Indy thread model.

 

 

OnDisconnect event not fired

 

IOCP works differently from default indy IOHandler. With the default Indy IOHandler, every connection runs in a thread and these threads are running all the time, checking if the connection is active, so if there is a disconnection, it's notified in a short period of time.

 

IOCP works differently, there is a thread pool which handles all connections, instead of 1 thread = 1 connection like indy does by default. For IOCP, the only way to detect if a connection is still alive is to try writing to the socket. If there is any error, it means that the connection is closed. There are 3 options to detect disconnections:

 

1. If you use TsgcWebSocketClient, you can enable it in Options property, CleanDisconnect := True (by default is disabled). If it's enabled, before the client disconnects it sends a message informing the server about disconnection, so the server will receive this message and the OnDisconnect event will be raised.

2. You can enable heartbeat on the server side, for example every 60 seconds, so it will try to send a ping to all clients connected and if there is any client disconnected, OnDisconnect will be called.

3. You can enable TCPKeepAlive and/or set KeepAliveTimeout on the server's IOHandlerOptions. These let the server itself detect a peer that has gone silent, for example because the client crashed or the network connection dropped without sending a close message, and close the connection, without depending on the client sending anything.