ノンブロッキングソケットのマニュアルページには、次の2つのケースが詳しく記載されています。
非ブロッキングソケットについて文書化されていないものは次のとおりです。
Send()がさらに1バイトのデータでEAGAIN/EWOULDBLOCKを返すと想定しても安全ですか?または、非ブロッキングプログラムは、最終的なEAGAIN/EWOULDBLOCKを取得するためにもう一度send()を試行する必要がありますか? EPOLLOUTウォッチャーが実際に「ブロック」状態になっていない場合は、ソケットにEPOLLOUTウォッチャーが接続されていることに応答するのではないかと心配しています。
明らかに、後者の戦略(決定的なものを得るために再試行する)には明確な動作がありますが、それはより冗長であり、パフォーマンスに打撃を与えます。
send
の呼び出しには、次の3つの結果が考えられます。
send
は成功し、受け入れられたバイト数を返します(おそらくあなたが要求したよりも少ない)。send
を呼び出した時点で、送信バッファーは完全にいっぱいです。send
ブロックsend
はEWOULDBLOCK
/EAGAIN
で失敗しますsend
が別のエラーで失敗するsend
が受け入れるバイト数が要求した量よりも少ない場合、これは結果として、送信バッファーが完全にいっぱいになったことを意味します。ただし、これは純粋に状況に応じたものであり、send
への今後の呼び出しに関しては権限がありません。send
によって返される情報は、send
を呼び出したときの現在の状態の単なる「スナップショット」です。 send
が戻ったとき、またはsend
を再度呼び出すときまでに、この情報はすでに古くなっている可能性があります。ネットワークカードは、プログラムがsend
内にある間、またはナノ秒後、またはその他の任意の時点でデータグラムをネットワークに配置する可能性があります。これを知る方法はありません。次の呼び出しが成功したとき(または失敗したとき)がわかります。
言い換えると、これはnotは、次のsend
の呼び出しがEWOULDBLOCK
/EAGAIN
(または、ソケットが非ブロックでない場合はブロックします)。 「決定的なEWOULDBLOCK
を取得する」と呼ばれるものまで試すのが正しいことです。
Send()が転送バッファーと同じ長さを返す場合、転送全体が正常に終了し、ソケットがブロッキング状態である場合とそうでない場合があります。
いいえ。ソケットは以前のモードのままです。この場合、非ブロッキングモードであり、以下で全体を通して想定されています。
Send()が-1を返し、errnoがEAGAIN/EWOULDBLOCKの場合、転送はいずれも終了せず、プログラムはソケットがブロックされなくなるまで待機する必要があります。
送信バッファがいっぱいでなくなるまで。ソケットは非ブロッキングモードのままです。
Send()がバッファサイズよりも小さい正の値を返す場合。
ソケット送信バッファには、それだけのスペースしかありませんでした。
Send()がさらに1バイトのデータをブロックすると想定しても安全ですか?
「[それが]ブロックするだろうと仮定する」ことは「安全」ではありません。そうではありません。ノンブロッキングモードです。 EWOULDBLOCKはそれを意味します持っているでしょうブロックされましたブロックモードで。
または、非ブロッキングプログラムは、最終的なEAGAIN/EWOULDBLOCKを取得するためにもう一度send()を試行する必要がありますか?
それはあなた次第です。 APIはあなたが決めたものは何でも動作します。
EPOLLOUTウォッチャーが実際にブロックされていない場合は、ソケットにEPOLLOUTウォッチャーを配置するのが心配です。
それは「それをブロックする」ことではありません。何もブロックしていません。ノンブロッキングモードです。その瞬間に送信バッファがいっぱいになりました。しばらくすると完全に空になる可能性があります。
何が心配なのかわかりません。保留中のデータがあり、最後の書き込みですべてが送信されなかった場合は、書き込み可能性を選択し、取得したときに書き込みます。そのような書き込みがすべてを送信する場合、次回は書き込み可能性を選択しないでください。
ソケットは通常、送信バッファがいっぱいでない限り書き込み可能です。したがって、スピンループが発生するだけなので、常に書き込み可能性を選択しないでください。