2015-05-22 6 views
9

Ich lese vom Sockel mit recv Funktion. Ich habe ein Problem, wenn keine Daten zum Lesen verfügbar sind. Mein Programm hört einfach auf. Ich habe festgestellt, dass ich Timeout mit select Funktion einstellen kann. Aber sieht aus, dass das Timeout sich auf die select Funktion selbst auswirkt und recv das nach dem select immer noch unstetig wartet.Einstellung Timeout zu recv-Funktion

fd_set set; 
struct timeval timeout; 
FD_ZERO(&set); /* clear the set */ 
FD_SET(s, &set); /* add our file descriptor to the set */ 
timeout.tv_sec = SOCKET_READ_TIMEOUT_SEC; 
timeout.tv_usec = 0; 
int rv = select(s, &set, NULL, NULL, &timeout); 
if((recv_size = recv(s , rx_tmp , bufSize ,0)) == SOCKET_ERROR) 
     { 
     ... 
     } 

Wie recv Funktion Rückkehr nach einigen timout fragen?

Antwort

6

Sie sollten Rückgabewert von select überprüfen. select wird 0 bei Timeout Rückkehr abgelaufen ist, so sollten Sie sich für Fehler überprüfen und recv rufen nur, wenn select positiver Wert zurückgegeben:

Bei Erfolg select() und pselect() geben die Anzahl der Datei-Deskriptoren in der enthaltenen drei zurückgegebene Deskriptorsätze (dh die Gesamtzahl der Bits, die in readfds, writefds, exceptfds gesetzt sind), die Null sein können, wenn das Zeitlimit abläuft, bevor etwas Interessantes passiert.

int rv = select(s + 1, &set, NULL, NULL, &timeout); 
if (rv == SOCKET_ERROR) 
{ 
    // select error... 
} 
else if (rv == 0) 
{ 
    // timeout, socket does not have anything to read 
} 
else 
{ 
    // socket has something to read 
    recv_size = recv(s, rx_tmp, bufSize, 0); 
    if (recv_size == SOCKET_ERROR) 
    { 
     // read failed... 
    } 
    else if (recv_size == 0) 
    { 
     // peer disconnected... 
    } 
    else 
    { 
     // read successful... 
    } 
} 
+0

Dieses Codebeispiel einen Fehler hat ... die Zeile das liest: 'int rv = auswählen (s, & set, NULL, NULL, & Timeout);' sollte lesen 'int rv = auswählen (s + 1, & set, NULL, NULL, & Timeout);' – drbobdugan

+0

Vielen Dank, Sie Wirklich richtig! 'nfds' ist der Dateideskriptor mit der höchsten Nummer + 1. –

21

Eine weitere Möglichkeit, einen Timeout auf recv() selbst ohne setzen select() Verwendung ist setsockopt() zu verwenden, um die SO_RCVTIMEO Option der Buchse (auf Plattformen, die es unterstützen) einzustellen.

Unter Windows wird der Code würde wie folgt aussehen:

DWORD timeout = SOCKET_READ_TIMEOUT_SEC * 1000; 
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)); 

//... 

recv_size = recv(s, rx_tmp, bufSize, 0); 
if (recv_size == SOCKET_ERROR) 
{ 
    if (WSAGetLastError() != WSAETIMEDOUT) 
     //... 
} 

Auf anderen Plattformen aussehen würde der Code wie diese statt:

struct timeval timeout; 
timeout.tv_sec = SOCKET_READ_TIMEOUT_SEC; 
timeout.tv_usec = 0; 
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); 

//... 

recv_size = recv(s, rx_tmp, bufSize, 0); 
if (recv_size == -1) 
{ 
    if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) 
     //... 
} 
+1

FYI Diese Lösung funktioniert nur auf Windows-Plattformen, sie kann nicht auf Unix/Linux/OSX-Plattformen verwendet werden. – drbobdugan

+1

@drbobdugan: Windows ist nicht die einzige Plattform, die 'SO_RCVTIMEO' unterstützt, obwohl auf anderen Plattformen der Eingabeparameter normalerweise eine' timeval'-Struktur ist. [Linux implementiert 'SO_RCVTIMEO' (und' SO_SNDTIMEO')] (http://man7.org/linux/man-pages/man7/socket.7.html). [Das gleiche gilt für OSX] (https://developer.apple.com/library/ios/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setsockopt.2.html). –

+0

Ihre Lösung wird auf einer Linux/Unix/OSX-Plattform nicht funktionieren, da sie Code-Fragmente wie DWORD, WSAGetLastError() enthält, die Windows-Artefakte sind. – drbobdugan

Verwandte Themen