2009-05-14 15 views
10

は、ここで私が働いているいくつかのコードの簡易版です:私たちはRECVへの最初の呼び出しが成功したと仮定した場合MSG_PEEKの非ブロックrecvが成功した場合、MSG_PEEKのない次のrecvも成功しますか?

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); 
} 

、1と32の間の値を返す、それは安全で2回目の呼び出しと仮定することです成功するでしょうか? ret2はret1未満になることはありますか?どの場合?

recvへの2回目の呼び出しでは、信号が出力されないこと、ENOMEMが設定されないなどのエラー条件がないことを前提としています。また、他のスレッドがfd 。

私は、Linux上だけど、MSG_DONTWAITは、私は信じて、ここでの唯一のLinux固有のものである。右fnctlは、他のプラットフォームで以前に設定されたと仮定します。)

答えて

1

私はEAGAINについてはよく分かりませんEBADFやECONNRESETは可能だと思います。

+0

他のスレッドが 'recv'の2回の呼び出しの間に' fd'を終了しない限り、 'EBADF'は可能ではありません。 – pts

7

POSIX規格では、MSG_PEEKでは「データは未読として扱われ、次のrecv()または同様の関数はこのデータを返す」と規定されています。これは、ret2が-1でなければret1と同じになることを意味しているようです。

5

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

あなたのアプリがマルチスレッドでない場合、またはfdがこれらの呼び出しでのみ使用されるように設計されている場合は、これを無視できます。しかし、これが危険な場合は、2つの呼び出しをロック機構の中に置くべきです。

+3

他の誰かが 'recv'を呼び出す間にデータを取得することは、シングルスレッドのプログラムでも可能です。同じソケットファイルディスクリプタを開いた別のプロセスがデータを取得する可能性があります。同じプロセスのシグナルハンドラもデータを取得する可能性があります。 (幸運なことに、コード内のシグナルハンドラは通常制御が簡単です。) – pts

0

簡単なケースでは、次のrecvはret1のバイト数を返します(ret1がエラーでなかった場合)。ただし、マルチスレッド設計の場合、常に正しいとは限りません。

2

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

関連する問題