SAN のソケット ハンドルの複製
異なるプロセスで実行される複数のアプリケーションは、Windows ソケット スイッチを使用し、共有基になるソケットに対して操作を実行できます。 ただし、その共有基になるソケットの操作を実行できるのは、一度に 1 つのアプリケーションのみです。
共有基になるソケットを使用するには、アプリケーションは、次のいずれかの方法で、その基になるソケットへの複数のハンドルを取得する必要があります。
直接、Windows ソケット WSADuplicateSocket 関数を呼び出して
呼び出しは、制御プロセス (ソケットを作成したプロセス) のコンテキストで行われます。
間接的に、Win32 DuplicateHandle 関数を呼び出して
呼び出しは、(ソケットを作成したプロセス以外の) 非制御プロセスのコンテキストで行われます。
ハンドル継承メカニズムを使用する
子プロセス (非制御プロセス) では、親プロセス (制御プロセス) で作成したハンドルのすべてまたは一部を継承します。
正常な接続の閉鎖中
制御プロセスのアプリケーションがソケットを閉鎖し、一部のデータの送信がまだ残っている場合、この残っているデータは Windows ソケット DLL にバッファーされます。 その後、システム サービス プロセス (非制御プロセス) のコンテキスト内の別のアプリケーションがこのデータを送信します。
Windows ソケット スイッチは、TCP/IP プロバイダーと組み合わせて、上記の各条件を検出して処理を行います。 このスイッチを使用すると、共有ソケットのデータ転送または状態の変更の操作を一度に 1 つのプロセスで実行できます。 必要に応じて、基になるソケットの制御を動的にスワップして、リクエストされた操作を実行します。 スイッチは、共有ソケットで異なるプロセスを実行するリクエストをシリアル化し、その操作を先入れ先出し (FIFO) 順序で実行します。 基になるソケットの制御を別のプロセスにスワップする前に、スイッチは進行中のすべての操作が完了するまで待機します。 論理的に、スイッチは、制御されていないプロセスが条件を満たす操作をリクエストするとすぐに、基になるソケットの制御を制御プロセスから分けます。 制御を取り除いた後、元の制御プロセスが修飾操作をリクエストした場合、スイッチは元の制御プロセスを非制御プロセスのように扱います。 制御されていないプロセスがデータ転送または状態変更操作の重複であるソケット ハンドルを実際に使用するまで、スイッチは重複しているソケット ハンドルへアクションを実行しません。
特定の基になるソケットへのアクセスを共有するすべてのプロセスに、スイッチと適切な SAN サービス プロバイダーの両方が読み込まれます。 スイッチがソケットを共有するすべてのプロセスでは、独自のソケット コンテキストと接続状態情報が保持されます。 SAN サービス プロバイダーは、特定の時点で基になるソケットを制御するプロセス内でのみ、ソケット コンテキストと接続状態情報を維持しなければなりません。 SAN サービス プロバイダーは、次のシーケンスで説明している通り、スイッチにスワップが必要になるたびに、現在の制御プロセスから次の制御プロセスへのコンテキストと接続状態情報の制御をスワップする必要があります。 スワップに必要なリソースの量を最小限に抑えるために、SAN サービス プロバイダーは、基になるソケットを共有するすべてのプロセスにそのコンテキストと接続状態情報を保存できます。
スイッチは、アプリケーションがConect関数またはListen関数を呼び出すまで、アプリケーション ソケットに対応する SAN ソケットを 作成しないため、アプリケーション ソケットが接続される または リッスン する前に、SAN サービス プロバイダーがスワップ操作を実行することをリクエストできません。 アプリケーション ソケットが接続またはリッスンされた後でも、スイッチがソケットの SAN サービス プロバイダースワップ制御をリクエストする前に、次のいずれかの条件を満たすことが必要です。
ソケットを制御しないプロセスでは、データ転送を開始します。 SAN サービス プロバイダーは、制御プロセスによって開始したすべてのデータ転送操作を完了するまで、ソケットの制御をスワップしません。
ソケットを制御しないプロセスは、WSAAccept、WSPAccept、または AcceptEx 関数を呼び出して、リッスン しているソケットで接続受け入れ操作を開始します。 SAN サービス プロバイダーは、制御プロセスによって開始したすべてのリクエストを受け入れるまで、ソケットの制御をスワップしません。
スイッチは、次の手順を実行して、接続された SAN ソケットの制御を制御プロセスから次の制御プロセスにスワップします (スワップ プロセスの概要については、WSPDuplicateSocket 関数のドキュメントの「解説」セクションの表を参照してください)。
スイッチは、制御プロセス中のアプリケーションからの新しいリクエストの処理を中断します。 SAN ソケットで進行中のすべての送信操作と RDMA 操作が完了すると、スイッチは SAN サービス プロバイダーの WSPSend 関数を呼び出して接続されたピアにメッセージを送信してセッションの中断をリクエストし、SAN サービス プロバイダーの WSPDeregisterMemory 関数を呼び出して送信操作に使用されるすべてのローカル バッファーを解放します。 その結果、ピア接続のスイッチは、新しいアプリケーションのリクエストの処理を中断し、SAN ソケットで進行中のすべての送信操作と RDMA 操作が完了するまで待機し、すべての RDMA メモリを解放します。 ピア接続では、次にセッションが中断されたことを示す応答メッセージを送信します。 この確認メッセージを受信すると、ローカル エンドポイントのスイッチが SAN サービス プロバイダーの WSPDeregisterRdmaMemory 関数を呼び出して、すべての RDMA メモリを解放します。 この時点で、接続の両方のエンドポイントにある SAN ソケットは、受信リクエストのみを保留中にすることができます。 これらの受信リクエストはメインセッションの再有効化を許可するために、リモート ピアの SAN ソケットで保留中です。 制御プロセスのローカル SAN ソケットでの受信リクエストは、次の手順で完了します。 接続を中断している間、リモート ピア接続のスイッチは、新しいブロック要求または重複要求をキューに入れ、新しい非ブロッキング送信をSO_SNDBUF設定までバッファーし、バッファー制限に達した後に新しい非ブロック送信に失敗し、WSAEWOULDBLOCK を使用して新しい非ブロッキング受信をすべて失敗します。 制御プロセスのローカル・スイッチは、アプリケーション・ソケット上の新規リクエストを、プロセスがソケット制御をしていないかのように処理します。
セッションが中断されると、スイッチは制御プロセスで SAN サービス プロバイダーの WSPDuplicateSocket 関数を呼び出して、SAN サービス プロバイダーに、次に制御するプロセスのアドレス空間にソケット コンテキストを転送するように 指示します。 スイッチは、WSPDuplicateSocket の dwProcessId パラメーター で次に制御するプロセスを指定します。 WSPDuplicateSocket 関数は、WPUCompleteOverlappedRequest 関数を呼び出して、成功状態と 0 バイトでソケット上のすべての未処理の受信要求を完了する必要があります。 SAN サービス プロバイダーは、これらのリクエストに関わるすべてのバッファーも自動的に解放する必要があります。 スイッチは WSPDuplicateSocket が返された後に SAN ソケットに対してそれ以上の操作をリクエストしないため、SAN サービス プロバイダーはすべてのバッファーを解放します。 次の手順で説明する通り、可能な 唯一の例外は WSPCloseSocket 関数呼び出しです。 WSPDuplicateSocket が戻った後、スイッチは、lpProtocolInfo 出力パラメーターがしますWSAPROTOCOL_INFOW構造体の dwProviderReserved メンバーに値を保存します。 スイッチはこの値を使用して、次に制御するプロセスのコンテキストで基になるソケットを識別します。 したがって、dwProviderReserved の値は、システム上のすべてのプロセスで、基になるソケットとその接続を一意に識別する必要があります。 さらに、この値は、WSPDuplicateSocket の dwProcessId パラメーターでスイッチが指定したプロセスのコンテキストでのみ有効である必要があります。
次に制御するプロセスのアドレス空間にソケット コンテキストが転送されると、スイッチは、次に制御するプロセスの コンテキストで SAN サービス プロバイダーの WSPSocket 関数を呼び出します。 この呼び出しでは、スイッチは、WSPDuplicateSocket 呼び出しで返された基になるソケットの値を、lpProtocolInfo 入力パラメーターが指す WSAPROTOCOL_INFOW 構造体の dwProviderReserved メンバーに渡します。 次に制御するプロセスが SAN ソケットの作成を要求しなかった場合、SAN サービス プロバイダーは新しいソケットを作成し、WPUCreateSocketHandle 関数を呼び出して、新しいソケットの必要に応じてハンドルを取得する必要があります。 次に制御するプロセスのコンテキストで SAN ソケットが作成された場合、SAN サービス プロバイダーは以前のソケットを再アクティブ化し、以前に使用されたソケットと同じ記述子を返すことができます。 この場合、SAN サービス プロバイダーは WPUCreateSocketHandle を呼び出すのではなく、スイッチが提供した元のソケット ハンドルを引き続き使用する必要があります。 または、SAN サービス プロバイダーは、以前にプロセスにソケットが存在していたかどうかに関わらず、新しいソケットを作成することができます。 この場合、スイッチは、前のソケット記述子を破棄するために、次の制御プロセスのコンテキストで SAN サービス プロバイダーの WSPCloseSocket 関数を呼び出さなければなりません。
スイッチは、次の制御プロセスでアプリケーションからの新しいリクエストの処理を再開します。
スイッチは、セッションを中断する必要がない点を除いて、同様の方法でリッスン ソケットを複製します。 スイッチは、制御プロセスで SAN サービス プロバイダーの WSPDuplicateSocket 関数を呼び出す前に、アプリケーションの accept 呼び出しと AcceptEx 呼び出しによって開始されたすべての WSPAccept 呼び出しが完了するまで待機します。
スイッチは、SAN サービス プロバイダーの WSPDuplicateSocket 関数を呼び出す前に SAN ソケットでの新しいリクエストの処理を中断するため、SAN サービス プロバイダーは、制御プロセスのローカル エンドポイントに関連付けられているすべてのリソースを解放できます。 SAN サービス プロバイダーは、基になる接続を終了することも可能です。 SAN サービス プロバイダーが制御プロセスで基になる接続を閉鎖する場合、SAN サービス プロバイダーは、スイッチが次の制御プロセス内で SAN サービス プロバイダーの WSPSocket 関数を呼び出した後に、接続を再確立しなければなりません。 WSPSocket 呼び出しが戻った後、制御プロセス内の SAN ソケットは、制御プロセスの SAN ソケットが SAN サービス プロバイダーのWSPDuplicateSocket 関数を呼び出す前だったのと同じ状態である必要があります。
SAN NIC がエンドポイント間で異なるプロセスで実行されるリソースの共有をサポートしている場合、SAN サービス プロバイダーは、WSPDuplicateSocket 呼び出しを受信する前に、制御プロセス内のローカル エンドポイントのリソースを解放する必要はありません。 このような場合、ローカル エンドポイントに関わる SAN ソケットはメインスイッチが次の制御プロセスからソケット コンテキストをスワップするか、SAN サービス プロバイダーの WSPCloseSocket 関数を呼び出してソケットを明示的に閉じるまで、以前の制御プロセスでは無効になります。 最初にソケットを作成したプロセス (通常は接続を閉じる) でソケットへの最終的なアクセスを実行するアプリケーションがほとんどのため、SAN サービス プロバイダーは、スイッチがソケットの制御を次の制御プロセスにスワップした後に制御プロセスでソケット コンテキストを保持すると、パフォーマンスを向上させることができます。
いずれの場合も、SAN ソケット記述子はメインスイッチが SAN サービス プロバイダーの WSPCloseSocket 関数を呼び出してソケットを明示的に閉じるまで有効にしなければなりません。 SAN サービス プロバイダーが WSPDuplicateSocket 呼び出しを受信する前に特定のプロセスでソケットのすべてのリソースを解放した場合でも、スイッチがその記述子で WSPCloseSocket を呼び出すまで、SAN サービス プロバイダーはソケットの記述子を再利用してはなりません。
予期しないプロセスの終了またはその他のエラー状態により、SAN サービス プロバイダーのソケット重複操作が中断されることがあります。 たとえば、リソースが不足すると、このような中断が発生する可能性があります。 スイッチは、他のエラー状況と同じように、このようなエラー状態を処理します。 必要に応じて、スイッチはすべてのプロセスの基になるソケットに関わるすべての記述子を閉じて、ソケットの接続を強制的に終了します。 可能であれば、リモート ピアの SAN サービス プロバイダーは、WSAECONNRE Standard Edition T などの適切なエラー コードを使用して受信データを受信する WSPRecv 呼び出しを完了する必要があります。 このエラー コードは、接続終了をリモート ピアに通知するものです。 リモート ピアのスイッチがこの接続終了の信号を受信しない場合、中断をリクエストしたシステムが失敗した場合、リモート ピアのスイッチは中断された接続をタイムアウトします。