ピア側のソケットが閉じられると、パイプ破損エラーがスローされることを知っています。
しかし、私のテストでは、ピア側が閉じられているときにこの側ですぐに「送信」呼び出しを行っても、パイプ破損エラーが常に発生するわけではないことに注意しました。
例えば。:
ピア側でソケットを閉じた後(closeを呼び出してクリーンクローズを試み、ピアを殺して異常なクローズを試みました)、40バイトを送信しようとしても、パイプが壊れることはありませんが、 40000バイトを送信すると、すぐに破損したパイプエラーが発生します。
パイプが破損する原因は何ですか?また、その挙動を予測できますか?
ネットワークが観測されるまでに時間がかかることがあります-終了後、ポート宛てのパケットがすべてデッドと見なされるまでの合計時間は、通常約2分(はい、分!)です。エラー状態はある時点で検出されます。わずかな書き込みで、システムのMTU内にいるため、メッセージは送信のためにキューに入れられます。大量の書き込みを行うと、MTUよりも大きくなり、システムは問題をより迅速に発見します。 SIGPIPEシグナルを無視した場合、関数は、破損したパイプでEPIPEエラーを返します-接続の破損が検出された時点で。
ソケットの現在の状態は、「キープアライブ」アクティビティによって決定されます。あなたの場合、これは、send
呼び出しを発行しているときに、keep-alive
アクティビティがソケットがアクティブであることを通知するため、send
呼び出しが必要なデータ(40バイト)バッファーに戻り、エラーを返さずに戻ります。
大きなチャンクを送信している場合、送信呼び出しはブロッキング状態になります。
Send manページでもこれが確認されています。
メッセージがソケットの送信バッファーに収まらない場合、send()は通常、ソケットが非ブロッキング入出力モードに設定されていない限りブロックします。非ブロッキングモードでは、この場合EAGAINを返します
そのため、使用可能な空きバッファをブロックしているときに、相手側が存在しないことが(キープアライブメカニズムによって)呼び出し元に通知されると、送信呼び出しは失敗します。
上記の情報では正確なシナリオを予測することは困難ですが、これが問題の原因であると考えています。
40バイトはパイプバッファーに収まり、40000バイトは収まらないのでしょうか?
編集:
閉じたパイプに書き込もうとすると、送信プロセスにSIGPIPEシグナルが送信されます。信号がいつ送信されるのか、またはパイプバッファーがこれにどのような影響を与えるのか、正確にはわかりません。 sigaction呼び出しで信号をトラップすることで回復できる場合があります。
ピアがクローズするとき、送信を停止するだけなのか、送信と受信の両方を停止するのかがわかりません。TCPが許可するため、クローズとシャットダウンの違いを知っておく必要があります。ピアが送信と受信の両方を停止した場合、最初にいくつかのバイトを送信すると、成功します。しかし、ピアカーネルはRSTを送信します。したがって、その後いくつかのバイトを送信すると、カーネルはSIGPIPEシグナルを送信します。このシグナルをキャッチまたは無視した場合、送信が戻ったときに単にBroken pipeエラーが発生するか、そうでない場合、プログラムのデフォルトの動作がクラッシュします。