グレースフル シャットダウン、残留オプション、ソケット クロージャ

ソケットを閉じるソケット接続をシャットダウンする対象の明確化として、次の資料が提供されます。 ソケット接続のシャットダウンとソケットのクローズの違いを区別することが重要です。

ソケット接続をシャットダウンするには、2 つのエンドポイント間でプロトコル メッセージを交換する必要があります。以降はシャットダウン シーケンスと呼ばれます。 シャットダウン シーケンスの 2 つの一般的なクラスが定義されています。正常と中止 (ハードとも呼ばれます)。 正常なシャットダウン シーケンスでは、キューに登録されているが、まだ送信されていないデータは、接続が閉じられる前に送信できます。 中止シャットダウンでは、送信されていないデータはすべて失われます。 シャットダウン シーケンスの発生 (正常または中止) を使用して、シャットダウンが進行中であることを示すFD_CLOSE表示を関連付けられたアプリケーションに提供することもできます。

一方、ソケットを閉じると、ソケット ハンドルが割り当て解除され、アプリケーションがソケットを何らかの方法で参照したり使用したりできなくなります。

Windows ソケットでは、 シャットダウン 関数と WSASendDisconnect 関数の両方を使用してシャットダウン シーケンスを開始できます。一方、 closesocket 関数はソケット ハンドルの割り当てを解除し、関連付けられているリソースを解放するために使用されます。 ただし、 closesocket 関数によってシャットダウン シーケンスがまだ発生していない場合は、暗黙的にシャットダウン シーケンスが発生するという事実から、混乱が発生します。 実際、この機能に依存し、 closesocket を使用してシャットダウン シーケンスを開始し、ソケット ハンドルの割り当てを解除する、比較的一般的なプログラミングプラクティスとなっています。

この使用を容易にするために、ソケット インターフェイスはソケット オプション メカニズムを使用して制御を提供します。これにより、暗黙的なシャットダウン シーケンスを正常にするか中止するかをプログラマが示すことができます。また、 closesocket 関数が (すぐには完了しない) 残留して、正常なシャットダウン シーケンスが完了するまでの時間が必要かどうかを示すことができます。 これらの重要な違いと、この方法で closesocket を使用することの影響は、まだ広く理解されていません。

ソケット オプションSO_LINGERとSO_DONTLINGERに適切な値を設定することで、 closesocket 関数を使用して次の種類の動作を取得できます。

  • 中止シャットダウン シーケンス。 closesocket から即時に戻ります。
  • 正常なシャットダウン。シャットダウン シーケンスが完了するか、指定した時間間隔が経過するまで戻りを遅延させます。 正常なシャットダウン シーケンスが完了する前に時間間隔が期限切れになると、中止シャットダウン シーケンスが発生し、 closesocket が返されます。
  • 正常なシャットダウン、即時の戻り。シャットダウン シーケンスをバックグラウンドで完了できます。 これは既定の動作ですが、正常なシャットダウン シーケンスが実際に完了するタイミング (または正常なシャットダウン シーケンスが完了したかどうか) をアプリケーションで認識する方法はありません。

SO_LINGERおよびSO_DONTLINGER ソケット オプションの使用と関連する 残留 構造については、「 SOL_SOCKET ソケット オプション 」および 「残留 構造」のリファレンス セクションで詳しく説明します。

接続の破棄中に問題が発生する可能性を最小限に抑えるために使用できる手法の 1 つは、 closesocket によって開始される暗黙的なシャットダウンに依存しないようにすることです。 代わりに、シャットダウンまたは WSASendDisconnect という 2 つの明示的なシャットダウン機能のいずれかを使用します。 これにより、保留中のすべてのデータが受信されたことを示すFD_CLOSE表示がピア アプリケーションによって受信されます。 これを示すために、次の表に、アプリケーションのクライアント コンポーネントとサーバー コンポーネントによって呼び出される関数を示します。この関数は、クライアントが正常なシャットダウンを開始する役割を担います。

クライアント側 サーバー側
(1) シャットダウン (SD_SEND) を呼び出してセッションの終了を通知し、クライアントに送信するデータがもうありません。
(2) FD_CLOSEを受信し、正常なシャットダウンが進行中であり、すべてのデータが受信されたことを示します。
(3) 残りの応答データを送信します。
(ローカル タイミングの基準値のみ)FD_READを取得し、 recv を呼び出して、サーバーによって送信されたすべての応答データを取得します。 (4) シャットダウンを呼び出してSD_SEND)、サーバーに送信するデータがないことを示します。
(5) FD_CLOSE表示を受け取ります。 (ローカル タイミングの基準値のみ) closesocket を呼び出します。
(6) closesocket を呼び出します。