2

特定の時間間隔の後にソケットにデータを書き込もうとしています。2 つのスレッドがあり、1 つのスレッドは TCP 接続を維持し、もう 1 つのスレッドはデータを生成します。

データ生成モジュールは、データを生成し、共有メモリに書き込みます。サーバー スレッドは、共有メモリからデータを読み取り、それをクライアントに送信します。

しかし、データ生成スレッドが遅くなると、多くの計算が関係し、サーバー スレッドがクライアントに書き込もうとすると EWOULDBLOCK エラーが発生します。しかし、驚くべきことに、クライアント側から見ると、そのようなエラーはありません。

私が間違っていなければ、EWOULDBLOCK エラーは、サーバーがクライアントよりも高速であり、ソケット バッファーが再度書き込まれる前に完全に読み取られていない場合に返されます。しかし、ここでは全く逆です。

データ生成スレッドが完了するまでサーバー therad がスリープ状態に保たれていることが原因である可能性があります (データ スレッドの優先度が高い)。

誰かがここで何が起こっているのか説明できますか?

4

1 に答える 1

14

EWOULDBLOCK は、ノンブロッキング ソケットを使用していて、送信したいデータを保持するための十分なスペースがそのソケット用のカーネルの発信データ バッファーにない場合に返されます。これは、クライアントの読み取りが遅すぎる場合に発生する可能性がありますが、サーバーが一度に大量のデータを送信しようとした場合にも発生する可能性があります (クライアントが高速であっても)。たとえば、計算スレッドがデータの計算に長い時間を費やし、計算の最後に突然 300,000 バイトを超えるデータが一度に渡された場合、サーバー スレッドは次のようになります。

  1. 一部のデータが共有メモリ領域で利用可能であることを確認し、送信を開始します!
  2. len=300000 で send() を呼び出します。send() は、カーネルの発信ソケット データ バッファ (たとえば 131,072 バイト) に収まる限り多くのデータを吸収し、何を行ったかを示すために 131072 を返します。
  3. サーバー スレッドは、送信するデータが 168928 バイト残っていることを確認したため、len=168928 を指定して send() を再度呼び出します。この時点で、カーネルの発信ソケット データ バッファはまだ完全にいっぱいです (まだパケットを送信する機会がないため)。そのため、send() は EWOULDBLOCK を返します。

一般に、ノンブロッキング ソケットを使用している限り、コードで EWOULDBLOCK を処理する必要があります。私が通常それを処理する方法は次のとおりです。

  1. ソケットが書き込み準備完了を返すまで、select() (または poll() など) 内で待機します。
  2. select()/poll() がソケットが書き込み可能であることを示したら、利用可能なすべてのデータを送信するまで、または send() が EWOULDBLOCK を返すまで (どちらか早い方)、ソケットで send() を呼び出します。
  3. ステップ 2 で EWOULDBLOCK を取得した場合は、1 に進みます。

そうすれば、送信スレッドは常に発信データをカーネルにできるだけ速くフィードしますが、それ以上速くはなりません。つまり、ビジーループで CPU を浪費することはありませんが、不要なコードを挿入して時間を無駄にすることもありません。プロセスに遅れます。

于 2013-04-29T15:36:16.200 に答える