IOCP

Supported by

 

TsgcWebSocketServer

TsgcWebSocketHTTPServer

 

*カスタム Indy バージョンが必要です。

 

Windows用のIOCPは、Indyがデフォルトで行うように接続ごとに1つのスレッドを使用する代わりに、限られたスレッドプールを使用して数千の接続を処理できるAPIです。

Indyサーバーの IOCP を有効にするには、IOHandlerOptions プロパティに移動し、IOHandler タイプとして iohIOCP を選択します。


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 は IOCPの非同期リクエスト(オーバーラップ操作)に使用されるスレッドです。デフォルト値はゼロで、プロセッサ数に基づいてスレッド数が計算されます(ただしDelphi 7および2007ではcpucount関数がサポートされていないため、スレッド数は32に設定されます)。

WorkOpThreads は、リクエストを処理するために待機させておくワーカースレッドの最小数を設定します(デフォルトは 0)。IOCP スレッドは完了した操作を受け取って、その処理をこのプールに引き渡すだけなので、応答の遅いクライアントによってブロックされることはありません。このプールは、すべてのワーカーがすでに処理中の場合、あらかじめ決められた上限まで必要に応じて拡張されるため、事前にサイズを見積もっておく必要はありません。この値を大きくするのは、最初のリクエストが届く前にプールを準備しておきたい場合だけにしてください。そうすることで、接続が一度に集中する起動直後にスレッド生成のコストを支払わずに済みます。

2026.9.0 での変更点。 以前の WorkOpThreads は、すべての接続をこれらのスレッドのいずれか 1 つに固定していたため、同じ接続に対するすべてのリクエストは同じスレッドで実行され、WorkOpRoundRobin は新しい接続をそれらのスレッドにどのように振り分けるかを決めていました。この固定は廃止されました。リクエストの残りを待って停止している接続が、同じスレッドに割り当てられた他のすべての接続をブロックし、サーバーを停滞させていたためです。同じ接続に対するリクエストが異なるスレッドで実行されるようになったため、データベース接続やスレッドローカルキャッシュなど、スレッドごとに保持しているものが接続に追従するとみなしてはなりません。WorkOpRoundRobin は存在しなくなりました。コードから削除してください。また、Object Inspector で有効にしていた場合は、フォームの .dfm からも WorkOpRoundRobin の行を削除してください。そうしないとフォームが読み込まれません。

PartialRequestTimeout は、長さがすでにわかっている HTTP リクエストボディの残りをサーバーが待機する時間をミリ秒単位で指定します(デフォルトは 0 で、これは無効を意味します)。これを設定しない場合、リクエストボディが単一のコンプリーション内にすべて到達しない場合(例えば、複数のパケットに分けて送信された大きな POST など)、そのリクエストボディは黙って破棄され、応答なしに接続が閉じられます。この待機処理は、多数の接続を処理するためブロックしてはならない IOCP スレッド上では決して実行されず、上記で説明したワーカースレッドのプール上で実行されます。このプールは、あらかじめ決められた上限まで必要に応じて拡張されます。そのため、応答の遅い、あるいは応答しないクライアントがこのプールを使い果たして他の接続を妨げることはありません。

TCPKeepAlive は、オペレーティングシステムがアイドル状態の接続を調査し、応答がなくなったまま消失したピアを検出できるようにします(デフォルトは無効)。TCPKeepAlive.Enabled を True に設定すると、OS は接続が TCPKeepAlive.Time 秒(デフォルトは 60)アイドル状態になった後に調査を開始し、ピアが応答するか接続が切断されるまで TCPKeepAlive.Interval 秒(デフォルトは 10)ごとにこれを繰り返します。

KeepAliveTimeout は、指定した秒数(デフォルトは 0 で、これは無効を意味します)を超えてアイドル状態が続いた接続を閉じます。影響を受けるのはアイドル状態の接続のみで、読み取り中のリクエストや書き込み中のレスポンスがこのタイムアウトによって中断されることはありません。これは、デフォルトの 1 スレッド = 1 接続の IOHandler がサイレントな接続を解放する動作に最も近いものであり、オペレーティングシステムやピア側の協力に依存しません。

 

数千の接続を処理する必要がある場合、Windows サーバーで IOCP を有効にすることをお勧めします。サーバーが最大100の同時接続を処理するだけの場合は、デフォルトの Indy スレッドモデルで問題ありません。

 

 

OnDisconnect イベントが発生しない

 

IOCP はデフォルトの Indy IOHandler とは異なる動作をします。デフォルトの Indy IOHandler では、すべての接続がスレッドで実行され、これらのスレッドは常に実行中で接続がアクティブかどうかを確認します。切断があると短時間で通知されます。

 

IOCP は異なる動作をします。Indy がデフォルトで行うように 1 スレッド = 1 接続ではなく、すべての接続を処理するスレッドプールがあります。IOCP では、接続がまだ有効かどうかを検出する唯一の方法はソケットへの書き込みを試みることです。エラーが発生した場合、接続が閉じられていることを意味します。切断を検出するには 3 つのオプションがあります:

 

1. TsgcWebSocketClient を使用する場合は、Options プロパティで有効にできます。CleanDisconnect := True(デフォルトは無効)。有効にすると、クライアントは切断前に切断をサーバーに通知するメッセージを送信するため、サーバーはこのメッセージを受信し、OnDisconnect イベントが発生します。

2. サーバー側でハートビートを有効にできます。例えば60秒ごとに有効にすると、接続されているすべてのクライアントにpingを送信しようとし、切断されているクライアントがある場合はOnDisconnectが呼び出されます。

3. サーバーの IOHandlerOptions で TCPKeepAlive を有効にしたり、KeepAliveTimeout を設定したりできます。これにより、例えばクライアントがクラッシュした場合やネットワーク接続がクローズメッセージを送信せずに切断された場合など、応答がなくなったピアをサーバー自身が検出して接続を閉じることができ、クライアント側が何かを送信することに依存しません。