Come sapere quale caso si verifica quando recv non bloccante restituisce 0?

Aug 22 2020

Ho un semplice server TCP che funziona con socket non bloccanti.

Citazione dalla manpage di recv;

Quando un peer stream socket ha eseguito un arresto ordinato, il valore restituito sarà 0 (il tradizionale ritorno "end-of-file").

Il valore 0 può anche essere restituito se il numero richiesto di byte da ricevere da uno stream socket era 0.

Quando il socket è leggibile, lo leggo con questo codice:

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... */
}

Come possiamo sapere quale caso accade quando recvrestituisce 0?

Risposte

2 RobertoCaboni Aug 22 2020 at 15:29

Quando recvrestituisce 0 significa che il socket è stato chiuso con garbo dall'altro peer e può essere chiuso anche dalla tua parte. Quando non sono presenti dati nel socket, viene restituito -1 ed errnoè impostato su EAGAIN/ ETIMEDOUTe il socket non deve essere chiuso.

Infine, quando -1 viene restituito ed errnoè impostato su un valore diverso da EWOULDBLOCKo EAGAINil socket deve essere chiuso, perché si è verificato un errore irreversibile.
Per i socket non bloccanti significa che nessun dato è immediatamente disponibile quando recvviene chiamato. Per i socket bloccanti) significa tgat nessun dato è disponibile anche dopo il timeout ( SO_RCVTIMEO) precedentemente impostato con setsockopt()scaduto.


Come hai citato correttamente nella tua ultima modifica, 0 può essere restituito recvanche se la dimensione richiesta è 0.

Come possiamo sapere quale caso accade quando recv restituisce 0?

Basta testare la dimensione recv fornita (in questo caso è la dimensione di un array costante, quindi non ha molto senso; ma nel caso sia una variabile proveniente da altrove ...):

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 */
    }
}