非ブロッキングrecvが0を返したときにどのケースが発生するかを知る方法は?

Aug 22 2020

非ブロッキングソケットで実行される単純なTCPサーバーがあります。

recvのマンページからの引用;

ストリームソケットピアが正常なシャットダウンを実行すると、戻り値は0になります(従来の「ファイルの終わり」の戻り値)。

ストリームソケットから受信するように要求されたバイト数が0の場合も、値0が返されることがあります。

ソケットが読み取り可能になったら、次のコードで読み取ります。

uint8_t buf[2048];
ssize_t rlen;
while(1){
    rlen = recv(fd, buf, sizeof(buf), 0);
    if(rlen < 0){
        /* some error came, let's close socket... */
    }
    else if(rlen == 0){
        /* is there no bytes to read? do we need break; in here? */
        /* is socket closed by peer? do we need to close socket? */
    }
    /* some code that process buf and rlen... */
}

recv0を返すときにどのケースが発生するかをどのように知ることができますか?

回答

2 RobertoCaboni Aug 22 2020 at 15:29

recv0を返す場合は、ソケットが他のピアによって正常に閉じられており、自分の側からも閉じることができることを意味します。ソケットにデータが存在しない場合、-1が返さerrnoれ、EAGAIN/に設定されETIMEDOUT、ソケットを閉じる必要はありません。

最後に、-1が返され、とerrnoは異なる値に設定された場合、EWOULDBLOCKまたはEAGAINソケットを閉じる必要がある場合。これは、回復不能なエラーが発生したためです。
非ブロッキングソケットの場合、recvが呼び出されたときにすぐに利用できるデータがないことを意味します。ソケットをブロックする場合SO_RCVTIMEO)は、以前にsetsockopt()有効期限が切れて設定されたタイムアウト()の後でも、データが利用できないことを意味します。


前回の編集で正しく引用したrecvように、要求されたサイズが0の場合も、から0を返すことができます。

recvが0を返したときにどのケースが発生するかをどのように知ることができますか?

提供されたrecvサイズをテストするだけです(この場合は定数配列のサイズなので、あまり意味がありませんが、他の場所からの変数の場合は...):

bufSize = sizeof(buf);

/* further code that, who knows, might affect bufSize */

rlen = read(fd, buf, bufSize);
if(rlen < 0){
    if (errno != ETIMEDOUT && errno != EWOLUDBLOCK)
    {
        /* some error came, let's close socket... */
    }
}
else if(rlen == 0){
     if (bufSize != 0)
    {
        /* Close socket */
    }
}