web-dev-qa-db-ja.com

非ブロッキングsend()が部分的なデータのみを転送する場合、次の呼び出しでEWOULDBLOCKが返されると想定できますか?

ノンブロッキングソケットのマニュアルページには、次の2つのケースが詳しく記載されています。

  • Send()が転送バッファと同じ長さを返す場合、転送全体正常に終了し、ソケットは、0バイトを超える次の呼び出しをEAGAIN/EWOULDBLOCKに返す状態である場合とそうでない場合があります。転送。
  • Send()が-1を返し、errnoがEAGAIN/EWOULDBLOCKの場合、転送はありません終了し、プログラムはソケットが追加のデータ(epollの場合はEPOLLOUT)の準備ができるまで待機する必要があります。

非ブロッキングソケットについて文書化されていないものは次のとおりです。

  • Send()がバッファサイズよりも小さい正の値を返す場合。

Send()がさらに1バイトのデータでEAGAIN/EWOULDBLOCKを返すと想定しても安全ですか?または、非ブロッキングプログラムは、最終的なEAGAIN/EWOULDBLOCKを取得するためにもう一度send()を試行する必要がありますか? EPOLLOUTウォッチャーが実際に「ブロック」状態になっていない場合は、ソケットにEPOLLOUTウォッチャーが接続されていることに応答するのではないかと心配しています。

明らかに、後者の戦略(決定的なものを得るために再試行する)には明確な動作がありますが、それはより冗長であり、パフォーマンスに打撃を与えます。

15

send の呼び出しには、次の3つの結果が考えられます。

  1. 送信バッファには少なくとも1バイトが使用可能です→sendは成功し、受け入れられたバイト数を返します(おそらくあなたが要求したよりも少ない)。
  2. sendを呼び出した時点で、送信バッファーは完全にいっぱいです
    →ソケットがブロックしている場合、sendブロック
    →ソケットが非ブロッキングの場合、sendEWOULDBLOCK/EAGAINで失敗します
  3. エラーが発生しました(例:ユーザーがネットワークケーブルを引っ張った、ピアによって接続がリセットされた)→sendが別のエラーで失敗する

sendが受け入れるバイト数が要求した量よりも少ない場合、これは結果として、送信バッファーが完全にいっぱいになったことを意味します。ただし、これは純粋に状況に応じたものであり、sendへの今後の呼び出しに関しては権限がありません。
sendによって返される情報は、sendを呼び出したときの現在の状態の単なる「スナップショット」です。 sendが戻ったとき、またはsendを再度呼び出すときまでに、この情報はすでに古くなっている可能性があります。ネットワークカードは、プログラムがsend内にある間、またはナノ秒後、またはその他の任意の時点でデータグラムをネットワークに配置する可能性があります。これを知る方法はありません。次の呼び出しが成功したとき(または失敗したとき)がわかります。

言い換えると、これはnotは、次のsendの呼び出しがEWOULDBLOCK/EAGAIN(または、ソケットが非ブロックでない場合はブロックします)。 「決定的なEWOULDBLOCKを取得する」と呼ばれるものまで試すのが正しいことです。

27
Damon

Send()が転送バッファーと同じ長さを返す場合、転送全体が正常に終了し、ソケットがブロッキング状態である場合とそうでない場合があります。

いいえ。ソケットは以前のモードのままです。この場合、非ブロッキングモードであり、以下で全体を通して想定されています。

Send()が-1を返し、errnoがEAGAIN/EWOULDBLOCKの場合、転送はいずれも終了せず、プ​​ログラムはソケットがブロックされなくなるまで待機する必要があります。

送信バッファがいっぱいでなくなるまで。ソケットは非ブロッキングモードのままです。

Send()がバッファサイズよりも小さい正の値を返す場合。

ソケット送信バッファには、それだけのスペースしかありませんでした。

Send()がさらに1バイトのデータをブロックすると想定しても安全ですか?

「[それが]ブロックするだろうと仮定する」ことは「安全」ではありません。そうではありません。ノンブロッキングモードです。 EWOULDBLOCKはそれを意味します持っているでしょうブロックされましたブロックモードで。

または、非ブロッキングプログラムは、最終的なEAGAIN/EWOULDBLOCKを取得するためにもう一度send()を試行する必要がありますか?

それはあなた次第です。 APIはあなたが決めたものは何でも動作します。

EPOLLOUTウォッチャーが実際にブロックされていない場合は、ソケットにEPOLLOUTウォッチャーを配置するのが心配です。

それは「それをブロックする」ことではありません。何もブロックしていません。ノンブロッキングモードです。その瞬間に送信バッファがいっぱいになりました。しばらくすると完全に空になる可能性があります。

何が心配なのかわかりません。保留中のデータがあり、最後の書き込みですべてが送信されなかった場合は、書き込み可能性を選択し、取得したときに書き込みます。そのような書き込みがすべてを送信する場合、次回は書き込み可能性を選択しないでください。

ソケットは通常、送信バッファがいっぱいでない限り書き込み可能です。したがって、スピンループが発生するだけなので、常に書き込み可能性を選択しないでください。

4
user207421