1

私は自分のプロジェクトに async io を使用し、開いている各ソケットからフレームごとにデータを読み取ろうとする単一のスレッド ループを実行することにしました。これは非常にうまく機能し、全体として今のところ満足しています。問題は、非同期ソケットで発生している奇妙な問題です。

次のようなコードがあります。

accept a connection...
fcntl(O_NONBLOCK) on the client socket...

int rc;
if((rc = recv(socket))>0)
  process data
if rc == 0
  close socket and cleanup

問題は、接続が閉じられていないことを知っていても、時々 rc == 0 になることです。クリーンアップしなければ、アプリは通常どおり動作します。しかし、クリーンアップを行うと、クライアントは接続が確立される前に切断を受け取ります。

だから私の質問は:ソケットから正しい戻り値を取得するために、recvを実行する前にソケットの準備ができているかどうかを何とかチェックする必要がありますか?

私が見つけた情報のほとんどは決定的なものではありませんでした。select() への参照を見つけましたが、ソケットのステータスが変更されるまでブロックされているようですが、ソケットを非ブロックにする必要があります。

私が探しているのは、データがある場合はバッファに読み込まれ、recv は読み込まれたバイト数を返し、データがない場合は -1 を返し、ソケットが切断されている場合は返す必要があるという直感的な動作です。 0.

recv を呼び出して期待どおりに動作させる前に、ソケットに対して他に何かする必要がありますか?

4

1 に答える 1

1

まず、ソケット サーバーを使用して「すべて非同期」にするという重労働を引き受けることは、設計の良い出発点であり、非常に簡単にスケーラビリティを実現できます。

あなたの質問について。

recv() は次の値を返します。

  • recv() によって返される正の値は、バッファにコピーされたバイト数を示します (つまり、これらのバイトを実際に受信したことになります)。

  • recv() は、ソケットがリモート側によって閉じられた場合に 0 を返します。

  • 非同期ソケットの場合、recv() は -1 を返し、接続がまだ有効であるが消費される新しいデータがない場合、errno を EAGAIN または EWOULDBLOCK に設定します。ソケットで select() または poll() を呼び出して、データを待ちます。

  • そうしないと、一般的な接続障害により、recv() によって -1 が返されます。(そして、できることはソケットを閉じることだけです)。

したがって、「接続が閉じられていないことを知っていても、時々 rc == 0 になる」と言うとき、疑似コードは戻り値をチェックしているのではなく、(rc > 0) の結果をチェックしていると思われます。

これはあなたが望むロジックに近いです:

int rc;
rc = recv(s, buf, buffersize, 0);
if (rc == 0)
{
    /* socket closed by remote end */
    close(s); s=-1;
}
else if ((rc == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)) )
{
   // need to wait.  Call select() or poll()
}
else if (rc == -1)
{
    close(s); s=-1;
}
else
{
    ProcessNewData(s, buffer, rc);
}
于 2013-01-13T06:12:35.793 に答える