Zu Ihrer Information, wenn Sie Timeouts verwenden möchten, müssen Sie wissen, wie Sie mit Timeouts umgehen. Diese SO-Frage befasst sich mit der Behandlung, wenn eine Zeitüberschreitung auftritt
Trevor Boyd Smith
Antworten:
125
Der typische Ansatz besteht darin, mit select () zu warten, bis Daten verfügbar sind oder das Timeout auftritt. Rufen Sie nur an, recv()wenn tatsächlich Daten verfügbar sind. Um sicher zu gehen, setzen wir den Socket auch auf den nicht blockierenden Modus, um sicherzustellen, dass er recv()niemals auf unbestimmte Zeit blockiert. select()kann auch verwendet werden, um auf mehr als einen Socket gleichzeitig zu warten.
Wenn Sie viele offene Dateideskriptoren haben, ist poll () eine effizientere Alternative zu select().
Eine andere Möglichkeit besteht darin, ein Zeitlimit für alle Vorgänge am Socket mit socket.settimeout()festzulegen. Ich sehe jedoch, dass Sie diese Lösung in einer anderen Antwort explizit abgelehnt haben.
Verwendung selectist gut, aber der Teil, in dem Sie "Sie können nicht" sagen, ist irreführend, da es gibt socket.settimeout().
Nosklo
1
Es ist jetzt besser, aber ich sehe nicht, wo die Antwort "explizit abgelehnt" wurde.
Nosklo
7
Eine Warnung bei der Verwendung select: Wenn Sie auf einem Windows-Computer ausgeführt werden, sollten Sie selectsich auf die WinSock-Bibliothek verlassen, die die Gewohnheit hat, zurückzukehren, sobald einige Daten eingegangen sind , aber nicht unbedingt alle . Sie müssen also eine Schleife einbauen, um so lange anzurufen, select.select()bis alle Daten empfangen wurden. Wie Sie wissen, dass Sie alle Daten erhalten haben, müssen Sie (leider) herausfinden. Dies kann bedeuten, dass Sie nach einer Abschlusszeichenfolge, einer bestimmten Anzahl von Bytes suchen oder nur auf ein definiertes Zeitlimit warten.
JDM
4
Warum muss der Socket nicht blockiert werden? Ich denke nicht, dass dies für den Auswahlaufruf von Bedeutung ist (und er blockiert, bis ein Deskriptor gelesen werden kann oder das Timeout in diesem Fall abläuft), und recv () wird nicht blockiert, wenn die Auswahl erfüllt ist. Ich habe es mit recvfrom () versucht und es scheint korrekt zu funktionieren, ohne setblocking (0).
HankB
1
Wäre ready[0]nur falsch, wenn die Antwort des Servers keinen Text enthält?
Das Recv läuft nicht ab (zumindest als ich es ausprobiert habe). Nur für accept () ist eine Zeitüberschreitung aufgetreten.
Oren S
9
Die Zeit für socket.recv () scheint für mich in Ordnung zu sein, nachdem socket.settimeout () genau wie beabsichtigt eingestellt wurde. Mache ich das nach? Kann das noch jemand bestätigen?
Aeonaut
3
@Aeonaut Ich denke, dass diesmal die meiste Zeit recv () abläuft, aber es gibt eine Rennbedingung. In socket.recv () ruft Python (2.6) select / poll intern mit dem Timeout auf und recv () wird direkt danach aufgerufen. Wenn Sie also einen blockierenden Socket verwenden und zwischen diesen beiden Aufrufen der andere Endpunkt abstürzt, können Sie unbegrenzt an recv () hängen bleiben. Wenn Sie einen nicht blockierenden Socket verwenden, ruft Python select.select nicht intern auf, daher denke ich, dass Daniel Stutzbachs Antwort der richtige Weg ist.
emil.p.stanchev
4
Eigentlich habe ich wahrscheinlich falsch verstanden, als select () zurückgegeben wurde. Bitte kratzen Sie den vorherigen Kommentar. Im Beej-Handbuch heißt es, dass das oben Gesagte eine gültige Methode ist, um ein Timeout auf recv zu implementieren: beej.us/guide/bgnet/output/html/singlepage/…. Ich vertraue also darauf, dass es sich um eine maßgebliche Quelle handelt.
emil.p.stanchev
2
Ich bin mir nicht sicher, warum die verwendete Lösung selectbevorzugt wird, wenn diese Lösung ein Einzeiler ist (einfacher zu warten, weniger Risiko bei der Implementierung von Fehlern) und select unter der Haube verwendet (die Implementierung entspricht der Antwort von @DanielStuzbach).
Ich denke, er kommt in die gleiche Sache, in der ich bin, egal wie Sie diese Funktion anstoßen und anstoßen, sie hängt. Ich habe jetzt 2 oder 4 Timeouts ausprobiert und es hängt immer noch. Settimeout hängt auch.
Casey Daniel
1
Wenn Sie .settimeout()mehr als einmal aufrufen, können Sie die setdefaulttimeout()Methode an erster Stelle aufrufen .
mvarge
12
Sie können das Zeitlimit vor dem Empfang der Antwort festlegen und nach Erhalt der Antwort auf Keine zurücksetzen:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5.0)
data = sock.recv(1024)
sock.settimeout(None)
Das gesuchte Zeitlimit ist das Zeitlimit des Verbindungssockets und nicht das des primären Sockets, wenn Sie die Serverseite implementieren. Mit anderen Worten, es gibt ein anderes Zeitlimit für das Verbindungssocketobjekt, das die Ausgabe der socket.accept()Methode ist. Deshalb:
sock.listen(1)
connection, client_address = sock.accept()
connection.settimeout(5)# This is the one that affects recv() method.
connection.gettimeout()# This should result 5
sock.gettimeout()# This outputs None when not set previously, if I remember correctly.
Wenn Sie die Client-Seite implementieren, wäre dies einfach.
Wie in früheren Antworten erwähnt, können Sie Folgendes verwenden: .settimeout()
Zum Beispiel:
import socket
s = socket.socket()
s.settimeout(1)# Sets the socket to timeout after 1 second of no activity
host, port ="somehost",4444
s.connect((host, port))
s.send("Hello World!\r\n")try:
rec = s.recv(100)# try to receive 100 bytesexcept socket.timeout:# fail after 1 second of no activityprint("Didn't receive data! [Timeout]")finally:
s.close()
Sie können verwenden, socket.settimeout()welches ein ganzzahliges Argument akzeptiert, das die Anzahl der Sekunden darstellt. Setzt beispielsweise socket.settimeout(1)das Zeitlimit auf 1 Sekunde
Es bietet einen gepufferten Socket, der viele sehr nützliche Funktionen bietet, wie zum Beispiel:
.recv_until()#recv until occurrence of bytes.recv_closed()#recv until close.peek()#peek at buffer but don't pop values.settimeout()#configure timeout (including recv timeout)
Antworten:
Der typische Ansatz besteht darin, mit select () zu warten, bis Daten verfügbar sind oder das Timeout auftritt. Rufen Sie nur an,
recv()
wenn tatsächlich Daten verfügbar sind. Um sicher zu gehen, setzen wir den Socket auch auf den nicht blockierenden Modus, um sicherzustellen, dass errecv()
niemals auf unbestimmte Zeit blockiert.select()
kann auch verwendet werden, um auf mehr als einen Socket gleichzeitig zu warten.Wenn Sie viele offene Dateideskriptoren haben, ist poll () eine effizientere Alternative zu
select()
.Eine andere Möglichkeit besteht darin, ein Zeitlimit für alle Vorgänge am Socket mit
socket.settimeout()
festzulegen. Ich sehe jedoch, dass Sie diese Lösung in einer anderen Antwort explizit abgelehnt haben.quelle
select
ist gut, aber der Teil, in dem Sie "Sie können nicht" sagen, ist irreführend, da es gibtsocket.settimeout()
.select
: Wenn Sie auf einem Windows-Computer ausgeführt werden, sollten Sieselect
sich auf die WinSock-Bibliothek verlassen, die die Gewohnheit hat, zurückzukehren, sobald einige Daten eingegangen sind , aber nicht unbedingt alle . Sie müssen also eine Schleife einbauen, um so lange anzurufen,select.select()
bis alle Daten empfangen wurden. Wie Sie wissen, dass Sie alle Daten erhalten haben, müssen Sie (leider) herausfinden. Dies kann bedeuten, dass Sie nach einer Abschlusszeichenfolge, einer bestimmten Anzahl von Bytes suchen oder nur auf ein definiertes Zeitlimit warten.ready[0]
nur falsch, wenn die Antwort des Servers keinen Text enthält?da ist
socket.settimeout()
quelle
select
bevorzugt wird, wenn diese Lösung ein Einzeiler ist (einfacher zu warten, weniger Risiko bei der Implementierung von Fehlern) und select unter der Haube verwendet (die Implementierung entspricht der Antwort von @DanielStuzbach).Wie bereits erwähnt
select.select()
undsocket.settimeout()
wird funktionieren.Beachten Sie, dass Sie möglicherweise
settimeout
zweimal anrufen müssen, um Ihre Anforderungen zu erfüllen, zquelle
.settimeout()
mehr als einmal aufrufen, können Sie diesetdefaulttimeout()
Methode an erster Stelle aufrufen .Sie können das Zeitlimit vor dem Empfang der Antwort festlegen und nach Erhalt der Antwort auf Keine zurücksetzen:
quelle
Das gesuchte Zeitlimit ist das Zeitlimit des Verbindungssockets und nicht das des primären Sockets, wenn Sie die Serverseite implementieren. Mit anderen Worten, es gibt ein anderes Zeitlimit für das Verbindungssocketobjekt, das die Ausgabe der
socket.accept()
Methode ist. Deshalb:Wenn Sie die Client-Seite implementieren, wäre dies einfach.
quelle
Wie in früheren Antworten erwähnt, können Sie Folgendes verwenden:
.settimeout()
Zum Beispiel:Ich hoffe das hilft!!
quelle
Sie können verwenden,
socket.settimeout()
welches ein ganzzahliges Argument akzeptiert, das die Anzahl der Sekunden darstellt. Setzt beispielsweisesocket.settimeout(1)
das Zeitlimit auf 1 Sekundequelle
Versuchen Sie dies, es verwendet das zugrunde liegende C.
quelle
SO_RCVTIMEO
undSO_SNDTIMEO
.2
und warum100
? Welches ist der Timeout-Wert? In welcher Einheit?timeval = struct.pack('ll', sec, usec)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
usec = 10000 bedeutet 10 msquelle
Rufen Sie an: https://boltons.readthedocs.io/en/latest/socketutils.html
Es bietet einen gepufferten Socket, der viele sehr nützliche Funktionen bietet, wie zum Beispiel:
quelle