2

C++03 プログラムで書き込みを行っている TCP 経由のソケットがあります。場合によっては、write() の結果がゼロになることがあります。write(2) の man ページには、次のように記載されています。

成功すると、書き込まれたバイト数が返されます (ゼロは何も書き込まれていないことを示します)。エラーの場合は -1 が返され、errno が適切に設定されます。

それで、ゼロは本当にエラーがないことを意味し、すべてが書き込まれるまで write をもう一度呼び出す必要がありますか? 言い換えれば、書き込まれたバイト数がcount書き込みに渡したバイト数よりも少ない部分書き込みの場合と同じように、ゼロを処理して、合計書き込みcountバイト数に達するまで試行し続ける必要がありますか?

書き込みが連続してゼロを返し、まったく進行しないという無限ループに陥らないようにしたいのです。write を呼び出す前にファイル記述子の準備が整っていることを確認するために、最初に select() を呼び出す必要がありますか? ファイル記述子でブロッキングを有効にしました。

4

2 に答える 2

1

ブロッキング モードのwrite()orsend()は、ゼロの長さを指定した場合にのみゼロを返すことができます。これは、ほぼ間違いなく、プログラミング エラーです。

唯一の例外は、長さゼロの書き込みを使用してローカル TCP スタックを証明し、ECONNRESET などの保留中のエラーがあるかどうかを確認する場合です。

非ブロッキング モードでは、ゼロ長の書き込みはソケット送信バッファがいっぱいであることを意味します。これを取得したら、そのソケットを writefd として選択し始め、ソケットが書き込み可能になったときに書き込みを再試行する必要があります。それが成功した場合は、writefd としての選択を停止します。通常は writefd セットをまったく使用しないでください。ここにある場合を除き、ソケットはほとんど常に書き込みの準備ができているため、セレクターはすぐに戻ります。

于 2013-05-19T00:03:04.350 に答える
1

理論的には、最終的には通過するか、エラーが発生する可能性がありますが、念のため、無限ループに対する安全性を構築します。

ハードウェアを待機する呼び出しselectは機能する可能性があります (そして、ループバックしてすぐに再試行するよりも確かに優れています。これは、ほぼ確実に CPU 時間を無駄にします - どのくらい多くのことに依存します)、それはTOCTOU問題です - 他のプログラムあなたのシステムはあなたよりも前にそこに到達していて、(再び) に到達するまでに送信に使用できるシステム メモリがいっぱいになっている可能性がありますwrite

だから、私はこれらの行に沿って何かをします:

int write_zero_count = 0; 

while(not_all_written)
{
  int res;
  res = select(...);
  ... check if we can write, etc ... 
  res = write(...);
  if (res == 0)
  {
     write_zero_count++;
     if (write_zero_count > max_zero_writes)
     {
        error("Got many writes that sent zero bytes, not good");
        .... do other stuff to log and recover from error or exit? ...
     } 
  }
  else
  {
      write_zero_count = 0;
  }
}
于 2013-05-18T15:18:10.280 に答える