2009-05-14 5 views
10

Hier ist eine vereinfachte Version von Code auf ich arbeite:Wenn ein nonblocking recv mit MSG_PEEK erfolgreich ist, wird ein nachfolgendes recv ohne MSG_PEEK auch erfolgreich sein?

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

Wenn wir, dass der erste Aufruf recv annehmen gelingt es, einen Wert zwischen 1 und 32 zurückkehrt, ist es sicher, dass der zweite Anruf anzunehmen, wird auch gelingen? Kann ret2 jemals kleiner als ret1 sein? In welchen Fällen?

(Angenommen, es gibt keine anderen Fehlerbedingungen während des zweiten Recv-Aufrufs: kein Signal wird gesendet, es wird nicht ENOMEM usw. gesetzt. Außerdem wird angenommen, dass keine anderen Threads fd betrachten die einzige Linux-spezifische Sache hier.

ich auf Linux bin, aber MSG_DONTWAIT ist, glaube ich. Es sei angenommen, dass das Recht fnctl auf anderen Plattformen vorher gesetzt wurde.)

Antwort

1

ich bin nicht sicher über EAGAIN , aber denken Sie, dass EBADF oder ECONNRESET möglich sind.

+0

'EBADF' ist nicht möglich, wenn nicht ein anderer Thread' fd' zwischen den beiden Aufrufen von 'recv' schließt. – pts

7

Der POSIX-Standard gibt an, dass mit MSG_PEEK "die Daten als ungelesen behandelt werden und die nächste recv() - oder ähnliche Funktion diese Daten weiterhin zurückgibt." Das scheint zu bedeuten, dass, wenn ret2 -1 ist, dasselbe wie ret1 sein wird.

5

Sie müssen auch die Möglichkeit in Betracht ziehen, dass ein anderer recv-Aufruf in einem anderen Thread zwischen ret1 und ret2 aufgerufen werden kann. Dieser andere Aufruf würde Ihre Daten erhalten und ret2 ohne Daten oder unerwartet weniger Daten hinterlassen.

Wenn Ihre App nicht multi-threaded ist oder so konzipiert ist, dass die fd nur von diesen beiden Aufrufen verwendet wird, können Sie dies ignorieren. Wenn dies jedoch ein Risiko darstellt, sollten Sie die beiden Aufrufe in einen Sperrmechanismus einfügen.

+3

Jemand anders, der die Daten zwischen diesen beiden Aufrufen von 'recv' ergreift, ist sogar mit Singlethread-Programmen möglich: Ein anderer Prozess mit demselben Socket-Dateideskriptor kann die Daten erfassen. Ein Signal-Handler im selben Prozess kann auch die Daten erfassen. (Glücklicherweise sind Signalhandler in Ihrem Code normalerweise leicht zu kontrollieren.) – pts

0

Für Ihren einfachen Fall wird die nachfolgende recv ret1 Anzahl der Bytes zurückgeben (wenn ret1 kein Fehler war). Für Multi-Thread-Design ist es jedoch möglicherweise nicht immer wahr.

2

Ihr zweiter Aufruf von recv() ohne MSG_PEEK kann mit EINTR fehlschlagen oder unvollständige Daten zurückgeben, da sie durch ein Signal unterbrochen wurden.

Verwandte Themen