Wie kann ich versuchen, Daten aus Socket mit Timeout zu lesen? Ich weiß, wählt, pselect, poll, hat ein Timeout-Feld, aber bei Verwendung von "tcp fast-path" im TCP Reno Stack deaktiviert.
Die einzige Idee, die ich habe, ist recv (fd, ..., MSG_DONTWAIT) in einer Schleife zu verwenden
Sie können die Funktion setsockopt verwenden, um ein Zeitlimit für Empfangsvorgänge festzulegen:
SO_RCVTIMEO
Legt den Timeout-Wert fest, der .__ angibt. die maximale Zeitdauer einer Eingabe Funktion wartet, bis sie abgeschlossen ist. Es akzeptiert eine zeitliche Struktur mit der Anzahl Sekunden und Mikrosekunden Festlegen des Grenzwerts für die Dauer von Warten Sie auf eine Eingabeoperation an Komplett. Wenn eine Empfangsoperation für so viel Zeit ohne .__ gesperrt. zusätzliche Daten erhalten, soll es Rückkehr mit einer Teilzählung oder errno auf [EAGAIN] oder [EWOULDBLOCK] setzen, wenn nein Daten werden empfangen. Der Standardwert für diese Option ist Null, was anzeigt, dass eine Empfangsbetrieb darf nicht ausfallen . Diese Option nimmt eine zeitliche Struktur an . Beachten Sie, dass nicht alle Implementierungen Erlaube diese Option zu setzen.
// 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);
Berichten zufolge unter Windows sollte dies vor dem Aufruf von bind
erfolgen. Ich habe durch Experiment verifiziert, dass dies vor oder nach bind
unter Linux und OS X möglich ist.
Hier ist ein einfacher Code, um der recv-Funktion mithilfe der Umfrage in C Timeout 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;
}
Installieren Sie einen Handler für SIGALRM
und verwenden Sie dann alarm()
oder ualarm()
, bevor Sie eine regelmäßige Blockierung recv()
durchführen. Wenn der Alarm ausgelöst wird, gibt recv()
einen Fehler zurück, wobei errno
auf EINTR
gesetzt ist.
// funktioniert auch nach dem Bindevorgang für WINDOWS
DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);