Ich muss das Zeitlimit für die Socket-Recv-Methode von Python festlegen. Wie es geht?
Ich muss das Zeitlimit für die Socket-Recv-Methode von Python festlegen. Wie es geht?
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 er recv()
niemals auf unbestimmte Zeit blockiert. select()
kann auch verwendet werden, um auf mehr als einen Socket gleichzeitig zu warten.
import select
mysocket.setblocking(0)
ready = select.select([mysocket], [], [], timeout_in_seconds)
if ready[0]:
data = mysocket.recv(4096)
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.
select
ist gut, aber der Teil, in dem Sie "Sie können nicht" sagen, ist irreführend, da es gibt socket.settimeout()
.
select
: Wenn Sie auf einem Windows-Computer ausgeführt werden, sollten Sie select
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()
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()
und socket.settimeout()
wird funktionieren.
Beachten Sie, dass Sie möglicherweise settimeout
zweimal anrufen müssen, um Ihre Anforderungen zu erfüllen, z
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("",0))
sock.listen(1)
# accept can throw socket.timeout
sock.settimeout(5.0)
conn, addr = sock.accept()
# recv can throw socket.timeout
conn.settimeout(5.0)
conn.recv(1024)
.settimeout()
mehr als einmal aufrufen, können Sie die setdefaulttimeout()
Methode an erster Stelle aufrufen .
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.
sock.connect(server_address)
sock.settimeout(3)
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 bytes
except socket.timeout: # fail after 1 second of no activity
print("Didn't receive data! [Timeout]")
finally:
s.close()
Ich hoffe das hilft!!
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
Versuchen Sie dies, es verwendet das zugrunde liegende C.
timeval = struct.pack('ll', 2, 100)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
SO_RCVTIMEO
und SO_SNDTIMEO
.
2
und warum 100
? 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 ms
#! /usr/bin/python3.6
# -*- coding: utf-8 -*-
import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.settimeout(5)
PORT = 10801
s.bind(('', PORT))
print('Listening for broadcast at ', s.getsockname())
BUFFER_SIZE = 4096
while True:
try:
data, address = s.recvfrom(BUFFER_SIZE)
except socket.timeout:
print("Didn't receive data! [Timeout 5s]")
continue
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:
.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)