14

これが私が取り組んでいるいくつかのコードの簡略化されたバージョンです:

void
stuff(int fd)
{
    int ret1, ret2;
    char buffer[32];

    ret1 = recv(fd, buffer, 32, MSG_PEEK | MSG_DONTWAIT);

    /* Error handling -- and EAGAIN handling -- would go here.  Bail if
       necessary.  Otherwise, keep going.  */

    /* Can this call to recv fail, setting errno to EAGAIN?  */
    ret2 = recv(fd, buffer, ret1, 0);
}

recvへの最初の呼び出しが成功し、1〜32の値を返すと仮定した場合、2番目の呼び出しも成功すると仮定しても安全ですか?ret2をret1より小さくすることはできますか?どちらの場合?

(わかりやすくするために、recvへの2回目の呼び出し中に他のエラー状態がないと仮定します。シグナルが配信されない、ENOMEMが設定されない、などです。また、他のスレッドがfdを参照しないと仮定します。

私はLinuxを使用していますが、ここでLinux固有のものはMSG_DONTWAITだけだと思います。正しいfnctlが他のプラットフォームで以前に設定されていると想定します。)

4

5 に答える 5

10

POSIX標準では、次のことについて指定していますMSG_PEEK

データは未読として扱われ、次のrecv()または同様の関数は引き続きこのデータを返します

つまり、そうでない場合ret2-1、と同じになりますret1

于 2009-05-15T00:03:08.057 に答える
5

ret1 と ret2 の間で、別のスレッドで別の recv 呼び出しが呼び出される可能性も考慮する必要があります。その他の呼び出しはデータを取得し、ret2 にはデータがないか、予想外にデータが少なくなります。

アプリがマルチスレッド化されていない場合、または fd がこれら 2 つの呼び出しでのみ使用されるように設計されている場合は、これを無視できます。ただし、これがリスクである場合は、2 つの呼び出しをロック メカニズム内に配置する必要があります。

于 2009-05-15T00:18:09.363 に答える
2

EAGAIN についてはよくわかりませんが、EBADF または ECONNRESET は可能だと思います。

于 2009-05-14T18:12:50.427 に答える
2

MSG_PEEK を使用しない recv() への 2 回目の呼び出しは、シグナルによって中断されたため、EINTR で失敗するか、不完全なデータを返す可能性があります。

于 2010-12-22T13:46:46.583 に答える
0

単純なケースでは、後続のrecvは ret1 バイト数を返します (ret1 がエラーでない場合)。ただし、マルチスレッド設計の場合、常にそうであるとは限りません。

于 2009-07-08T08:44:53.010 に答える