2010-05-20 7 views
80

Wie kann ich versuchen, Daten vom Socket mit Timeout zu lesen? Ich weiß, wählen, pselect, abfragen, hat ein Timeout-Feld, aber die Verwendung von ihnen deaktiviert "TCP Fast-Pfad" in Tcp Reno-Stack.Linux: Gibt es einen Lese- oder Recv-Socket mit Timeout?

Die einzige Idee, die ich habe, ist recv zu verwenden (fd, ..., MSG_DONTWAIT) in einer Schleife

+0

Es gibt auch eine Option Threads verwenden :) aber Thread Signale benötigt noch – osgx

Antwort

147

Sie können das setsockopt Funktion ein Timeout setzen auf Operationen erhalten:

SO_RCVTIMEO

Setzt den Timeout-Wert, der die maximale Menge an Zeit, bis er eine Eingangs Funktion wartet angibt schließt ab. Es akzeptiert eine timeval Struktur mit der Anzahl der Sekunden und Mikrosekunden Angabe der Grenze, wie lange auf warten auf eine Eingabeoperation bis abgeschlossen. Wenn eine Empfangsoperation so lange blockiert ist, ohne dass zusätzliche Daten empfängt, muss mit einer Teilzählung oder errno auf [EAGAIN] oder [EWOULDBLOCK] zurückgesetzt werden, wenn keine Daten empfangen werden. Der Standardwert für diese Option ist Null, was bedeutet, dass eine Empfangsoperation keine Zeitüberschreitung haben soll. Diese Option benötigt eine zeitliche Struktur. Beachten Sie, dass nicht alle Implementierungen diese Option zulassen.

// LINUX 
struct timeval tv; 
tv.tv_sec = timeout_in_seconds; 
tv.tv_usec = 0; 
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv); 

// WINDOWS 
DWORD timeout = timeout_in_seconds * 1000; 
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout); 

// MAC OS X (identical to Linux) 
struct timeval tv; 
tv.tv_sec = timeout_in_seconds; 
tv.tv_usec = 0; 
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv); 

Reportedly unter Windows sollte dies vor bind Aufruf erfolgen. Ich habe durch das Experiment bestätigt, dass es entweder getan werden kann, vor oder nach bind unter Linux und OS X.

+2

Wird es für Linux 2.6 tcp funktionieren? UDP? – osgx

+5

Ja wird es. Vielen Dank – osgx

+0

Dies funktioniert nicht unter Windows .... – Mendes

0

für SIGALRM einen Handler installieren, dann alarm() oder ualarm() vor einem regulären recv() Blockierung verwenden. Wenn der Alarm ausgelöst wird, gibt recv() einen Fehler zurück mit errno, der auf EINTR festgelegt ist.

+8

Alarme (und Signale) sind der falsche Weg, um diese Aufgabe. Wenn ich tcp schnellen Pfad verwenden möchte, dann brauche ich minimale Latenz. Signale sind langsam. – osgx

+1

@osgx Das Signal tritt nur auf, wenn eine Zeitüberschreitung auftritt. –

13

Hier ist eine einfache Code-Zeit aus, um Ihre Funktion Recv in C unter Verwendung Umfrage hinzuzufügen:

struct pollfd fd; 
int ret; 

fd.fd = mySocket; // your socket handler 
fd.events = POLLIN; 
ret = poll(&fd, 1, 1000); // 1 second for timeout 
switch (ret) { 
    case -1: 
     // Error 
     break; 
    case 0: 
     // Timeout 
     break; 
    default: 
     recv(mySocket,buf,sizeof(buf), 0); // get your data 
     break; 
} 
-1

LINUX

struct timeval tv; 
tv.tv_sec = 30;  // 30 Secs Timeout 
tv.tv_usec = 0;  // Not init'ing this can cause strange errors 
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval)); 

WINDOWS

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

HINWEIS: Sie können diese Einstellung für die richtige Lauf vor bind() Funktionsaufruf gesetzt haben

+2

Diese Frage wurde bereits vor Jahren beantwortet. Welchen neuen Wert bringt Ihre Lösung? –

+0

Sie haben diese Einstellung vor den Funktionsaufruf bind() gesetzt, damit dieser Teil in Ans nicht erwähnt wird – vivek

Verwandte Themen