6

man私はページを読みましたが、write()失敗してerrnotoEAGAINまたはを設定すると、もう一度EINTR実行する可能性があることを理解write()しているので、次のコードを思いつきました。

  ret = 0;
  while(ret != count) {
    write_count = write(connFD, (char *)buf + ret,  count);
    while (write_count < 0) {
      switch(errno) {
        case EINTR:
        case EAGAIN:
          write_count = write(connFD, (char *)buf + ret,  count -ret);
          break;
        default:
          printf("\n The value of ret is : %d\n", ret);
          printf("\n The error number is : %d\n", errno);      
          ASSERT(0);
      }
    }
    ret += write_count;
  }

私はソケットで実行read()し、上記と同様に処理しています。Linuxとコンパイラを使用しています。write()read()gcc

4

4 に答える 4

6

そこには「自分を繰り返さないでください」という問題が少しあります。2つの別々の呼び出しwriteや2つのネストされたループは必要ありません。

私の通常のループは次のようになります。

for (int n = 0; n < count; ) {
    int ret = write(fd, (char *)buf + n, count - n);
    if (ret < 0) {
         if (errno == EINTR || errno == EAGAIN) continue; // try again
         perror("write");
         break;
    } else {
        n += ret;
    }
}

// if (n < count) here some error occurred
于 2012-04-26T19:45:05.567 に答える
3

EINTREAGAIN取り扱いはしばしばわずかに異なるはずです。EAGAINは常に、ソケットバッファの状態を表すある種の一時的なエラーです(または、より正確には、操作がブロックする可能性があります)。

ヒットしEAGAINたら、少しスリープするか、制御をイベントループに戻したいと思うでしょう(使用していると仮定します)。

EINTR状況によって少し異なります。アプリケーションがノンストップで信号を受信して​​いる場合は、アプリケーションまたは環境に問題がある可能性があります。そのため、私は何らかの内部eintr_maxカウンターを持っている傾向があるため、無限にループし続けるという理論的な状況にとらわれることはありません。にEINTR

Alnitakの答え(ほとんどの場合は十分です)も、 (簡潔にするために省略されている可能性がありますが)errnoによって破壊される可能性があるため、どこかに保存されているはずです。perror()

于 2012-04-27T20:59:07.787 に答える
2

正当な理由がないのにCPUをループして焼き尽くすだけpollではなく、記述子を使用したいと思います。これは、私が使用EAGAINする非ブロッキングの一種の「ブロッキングラッパー」です。write

ssize_t written = 0;

while (written < to_write) {
    ssize_t result;
    if ((result = write(fd, buffer, to_write - written)) < 0) {
        if (errno == EAGAIN) {
            struct pollfd pfd = { .fd = fd, .events = POLLOUT };
            if (poll(&pfd, 1, -1) <= 0 && errno != EAGAIN) {
                break;
            }
            continue;
        }
        return written ? written : result;
    }
    written += result;
    buffer += result;
}
return written;

poll戻り値以外の結果を実際にチェックしていないことに注意してください。write記述子に永続的なエラーがある場合、以下は失敗すると思います。

EINTRを使用して条件に追加するだけで、再試行可能なエラーとして含めることもできますがEAGAIN、実際にはI/Oを中断することをお勧めします。

于 2015-08-03T04:05:15.607 に答える
0

はい、よりクリーンな使用方法があります。引数としてwrite()aをとる書き込み関数のクラスです。FILE*つまり、最も重要なのはfprintf()fwrite()です。内部的には、これらのライブラリ関数はwrite()syscallを使用してジョブを実行し、やなどを処理EAGAINEINTRます。

ファイル記述子しかない場合は、いつでもを使用してファイル記述子をにラップFILE*できるfdopen()ため、上記の関数で使用できます。

ただし、落とし穴が1つありFILE*ます。通常、ストリームはバッファリングされます。これは、他のプログラムと通信していて、その応答を待っている場合に問題になる可能性があります。これにより、論理エラーがない場合でも、対応するビットfprintf()を延期することを決定したために、両方のプログラムがデッドロックする可能性があります。write()バッファリングをオフに切り替えたり、実際に呼び出しを実行fflush()する必要があるときはいつでもストリームを出力したりできます。write()

于 2015-02-01T10:34:51.057 に答える