msdn linkから setsockopt を見ていました。パラメータSO_RCVTIMEOに出くわしました。その説明は「受信呼び出しをブロックするためのタイムアウトをミリ秒単位で設定します」です。ソケットリッスン操作はイベント駆動型であると思いました。つまり、カーネルがNICカードからフレームを排出すると、プログラムソケットに通知します。ブロッキングがすべてですか?
2 に答える
recv および WSARecv 関数がブロックされています。それらはイベント駆動型ではありません (少なくとも呼び出しレベルでは)。ブロッキングに (SO_RECTIMEO
オプションで設定されたように) タイムアウトがある場合でも、コードに関する限り、それらはイベント ドリブンではありません。その場合、それらは単なる疑似ブロッキングです (タイムアウトの短さによっては、ほぼ間違いなく非ブロッキングです)。
WSARecv を呼び出すと、データを読み取る準備ができるまで待機します。データを読み取る準備ができていない間は、ただ待機します。これが、ブロックと見なされる理由です。
そのコア ネットワーキングはイベント ドリブンであることは間違いありません。内部では、コンピューターは本質的にイベント駆動型です。それがハードウェアの仕組みです。ハードウェア割り込みは本質的にイベントです。低レベルで起こっていることは、NICカードがOSに読み取りの準備ができていることを伝えているということです。そのレベルでは、それは確かにイベントベースです。
問題は、WSARecv がそのイベントを待機することです。
これはうまくいけば明確なアナロジーです。何らかの理由で家を出ることができないと想像してください。ここで、あなたの友人 F が隣に住んでいると想像してください。さらに、もう一人の友人 G があなたの家にいるとします。
ここで、G に質問が書かれた紙を渡して、それを F に持っていくように頼んだとします。
質問が送信されたら、F の応答を得るために G を送信することを想像してください。これは recv 呼び出しに似ています。G は、F が回答を書き留めるまで待ってから、それをあなたに持ってきます。F がまだ書き込んでいない場合、G はすぐに向きを変えて戻ってくるわけではありません。
ここからギャップが生まれます。Gは確かに「Fが書いた!」を認識しています。イベントですが、そうではありません。あなたは一枚の紙を直接見ているわけではありません。
タイムアウトを設定するということは、あきらめて戻ってくる前に、最大である程度の時間待つように G に指示していることを意味します。この状況では、G はまだ F の書き込みを待っていますが、F が数ミリ秒以内に書き込みを行わない場合x
、G は引き返し、手ぶらで戻ってきます。
基本的に、recv の疑似コードは漠然と次のようになります。
1) is data available?
1a) Yes: read it and return
1b) No: GOTO 2
2) Wait until an event is received
2a) GOTO 1
これが恐ろしく複雑な説明であることは承知していますが、私の要点は次のとおりです。recv はコードではなく、イベントと対話しています。recv は、これらのイベントのいずれかが受信されるまでブロックします。タイムアウトが設定されている場合、これらのイベントのいずれかが受信されるか、タイムアウトに達するまでブロックされます。
デフォルトでは、ソケットはイベント駆動型ではありません。それを有効にするには、追加のコードを記述する必要があります。代わりに、ソケットは最初はブロッキング モードで作成されます。これはsend()
、 、recv()
、またはへの呼び出しaccept()
が、要求された操作が終了するまでデフォルトで無期限に呼び出しスレッドをブロックすることを意味します。
の場合recv()
、これは、ソケットの受信バッファから少なくとも 1 バイトを読み取ることができるようになるまで、またはソケット エラーが発生するまで、呼び出し元のスレッドがブロックされることを意味します。 SO_RCVTIMEO
ブロッキング読み取りにタイムアウトを設定できるため、タイムアウトが経過する前に受信データが利用可能にならない場合、エラーrecv()
で終了します。WSAETIMEDOUT
タイムアウトを実装する別の方法は、代わりにソケットを非ブロッキング モードに設定し、タイムアウトを指定してioctlsocket(FIONBIO)
呼び出し、ソケットが読み取り可能な状態にあると報告された場合にのみorselect()
を呼び出し、ソケットが読み取り可能な状態にあると報告された場合にのみ呼び出すことです。書き込み可能な状態。ただし、これには、ソケットがブロック状態になり、操作がエラーで失敗するケースを管理するためにより多くのコードが必要になります。recv()
accept()
select()
send()
select()
WSAEWOULDBLOCK