ソケットの重複した I/O と、ブロック モードおよび非ブロック モード


概要


この資料では、ソケットの重複した I/O 属性とソケットのブロック モード、非ブロック モードの違いについて説明します。

詳細情報


ソケットが作成されると、デフォルトではブロッキングソケットになります。 ソケットモードをブロックモードから非ブロックモードに変更するには、ioctlsocket API呼び出し、WSAEventSelect、またはWSAAysncSelectでFIONBIOコマンドを使用できます。 Winsock呼び出しがすぐに完了できない場合、呼び出しは失敗し、nonblockingのソケットが終了するまでWSAEWOULDBLOCKエラーが返されます。そうでない場合は、操作がブロックされるまで呼び出しブロックが呼び出されます。


ソケットのオーバーラップI/O属性は、ソケットのブロックまたは非ブロックモードとは異なります。 現在のWinsockの実装は非ブロッキングソケットモードのために重複したI/O属性を必要としますが、それらは概念的に独立しており、それらのプログラミングモデルも異なります I/O属性を使用してソケットを作成するには、AMF APIまたはWSASocket APIをWSA_FLAG_OVERLAPPEDフラグセットで使用することができます。 重複したI/O操作がすぐに完了できない場合、呼び出しは失敗し、WSAGetLastErrorまたはGetLastErrorはWSA_IO_PENDINGまたはERROR_IO_PENDINGを返します。これは実際にはWSA_IO_PENDINGと同じ定義です。 詳細については、以下のサポート技術情報を参照してください。

179942 情報: 非ブロッキングソケットにはWSA_FLAG_OVERLAPPEDが必要
ソケットを作成した後は、ソケットを重なり合う属性を変更する方法はありません。 ただし、同一スレッド内のすべての連続ソケットの重複する属性を変更するために、すべてのソケットハンドルでSO_OPENTYPEオプションを使用してsetsockopt APIを呼び出すことができます。 デフォルトのSO_OPENTYPEオプション値は0で、重複した属性を設定します。 ゼロ以外のすべての値は、ソケット同期を行い、完了機能を使用できないように設定します。


ソケットのオーバーラップしたI/O属性を設定すると、ソケットがオーバーラップしたI/O操作を実行することはなくなります。 たとえば、WSARecv関数とWSASend関数の両方にNULLを指定し、WSARecvとWSASendのstructure関数を呼び出すか、または関数を呼び出すだけでは、ブロックはブロック内で完了します。 使用しているI/O関数によって、I/O関数を直線的に実行する必要があることを確認するには、使用する関数に応じて、そのI/Oが必要です。

重複した I/O

Winsock 1では、ソケットAPIを使用してオーバーラップソケットを作成し、Win32ファイルI/O APIのReadFile、ReadFileEx、WriteFile、WriteFileExを使用してソケットハンドルでオーバーラップI/Oを実行します。 Winsock 2では、WSAocketを使用してWSA_FLAG_OVERLAPPEDフラグを使用するか、単にソケットAPIを使用して、オーバーラップソケットを作成します。 上記のWin32ファイル入出力APIまたはWinsock 2のWSASend、WSASendTo、WSARecv、およびWSARecvFromを使用して、重複した入出力操作を開始できます。


SO_RCVBUFおよびSO_SNDBUFオプションを使用してTCPスタック受信および送信バッファーをゼロに設定する場合は、基本的に、入出力呼び出しで提供されたバッファーを使用して直接入出力を実行するようにTCPスタックに指示します。 したがって、オーバーラップソケットI/Oの非ブロック化の利点に加えて、もう1つの利点は、各I/O呼び出しに対してTCPスタックバッファとユーザバッファの間のバッファコピーを保存するため、パフォーマンスが向上します。 ただし、重複している操作のために送信され、オーバーラップする操作が完了する前に、ユーザーバッファにアクセスしないようにする必要があります。


重複した I/O 処理が完了しているかどうかを調べるには、次のいずれかの方法を使用します。

  • I/O 呼び出しで使用される重複した構造体にイベント ハンドルを指定し、イベント ハンドルからシグナルが送信されるのを待ちます。

  • I/O操作の状態をポーリングするには、GetOverlappedResultまたはWSAGetOverlappedResultを使用します。 Windows NTでは、イベント処理のイベント処理としてNULLを指定できます。 ただし、Windows 95では、オーバーラップする構造に手動リセットイベント処理を含める必要があります。 Windows 98およびWindows Millennium Edition(ME)上のWSAGetOverlappedResultは、Windows NTのように動作するように修正されており、重複構造内のNULLイベントハンドルで完了ステータスをポーリングすることもできます。
  • ReadFileEx、WriteFileEx、WSARecv、WSARecvFrom、WSASend、または WSASendTo を使用し、重複した I/O 処理の完了時に呼び出される完了関数を指定します。 完了関数アプローチを使用する場合、オーバーラップI/O操作を発行した後のある時点で、現在のスレッドを警告可能な待機状態にするには、シグナルのないシグナルを待つために、Win32待機関数またはWSAバージョンの待機関数を発行する必要があります。 重複したI / O操作が完了すると、完了関数が呼び出され、待機関数がWAIT_IO_COMPLETIONを返し、警告可能な待機スレッドが起動します。

  • GetQueuedCompletionStatus を使用し、重複した I/O 属性セットと共にソケットを Windows NT の IOCP (I/O Completion Port) に関連付けます。


    IOCPを使用すると、完了関数を提供したり、イベントハンドルを待ってシグナルを送ったり、オーバーラップした操作のステータスをポーリングする必要はありません。 IOCPを作成し、オーバーラップしたソケットハンドルをIOCPに追加すると、上記のI / O API(recv、recvfrom、send、またはsendtoを除く)のいずれかを使用してオーバーラップ操作を開始できます。 I/O完了パケットのGetQueuedCompletionStatus API待機時間には、ワーカースレッドブロックがあります。 重複したI/Oが完了すると、I/O完了パケットがIOCPに到着し、GetQueuedCompletionStatusが返されます。


    IOCPは、重複したI/O操作で非常に単純なスレッディングコードとブロッキングコードを使用して、スケーラブルで高スループットのサーバーを作成するためのWindows NTオペレーティングシステムのサポートです。 したがって、Windows NTのIOCPでオーバーラップソケットI / Oを使用すると、パフォーマンスが大幅に向上する可能性があります。

ブロック モードと非ブロック モード

ソケットが作成されると、デフォルトではブロッキングソケットがブロックされます。 ブロッキングモードのソケットI/O操作では、問題の操作が完了するまで、すべてのブロックで接続および受け入れ操作を行います。 ソケットの動作モードをブロックモードから非ブロックモードに変更するには、ioctlsocket API呼び出しでWSAAsyncSelect、WSAEventSelect、またはFIONBIOコマンドを使用できます。


WSAAsyncSelect では、ソケットの通知が Windows メッセージにマッピングされます。これは、シングル スレッドの GUI アプリケーションに最も適したモデルです。


WSAEventSelectは、WSAEnumNetworkEventsを使用して信号イベントのソケット通知の特性を決定し、イベントを通知してソケット通知をマップします。 これは、Windows NTサービスアプリケーションのように、メッセージポンプを持たない非GUIアプリケーションにとって便利なモデルです。


ioctlsocket API呼び出しのFIONBIOコマンドは、ソケットを非ブロックモードにもします。 しかし、選択APIを使用して、ソケットのステータスをポーリングする必要があります。

更新日: 重複したrecvを使用してSO_RCVBUFをゼロに設定することは、Windows 2000では不要です。Windows2000では、データをアプリケーションのrecvバッファーに直接コピーできます。 Windows 2000では、SO_SNDBUFをゼロに設定しても、1つのメモリコピーをWindows NT 4.0に保存すると、同じメリットが得られます。 アプリケーションが対応するスタックバッファを0に設定する場合、アプリケーションがいくつかの未処理の重複送信または受信を発行することも重要です。