Ho bisogno di impostare il timeout sul metodo recv socket di Python. Come farlo?
Ho bisogno di impostare il timeout sul metodo recv socket di Python. Come farlo?
Risposte:
L'approccio tipico consiste nell'usare select () per attendere che i dati siano disponibili o fino a quando non si verifica il timeout. Chiama solo recv()
quando i dati sono effettivamente disponibili. Per sicurezza, impostiamo anche il socket in modalità non bloccante per garantire che recv()
non si bloccherà mai indefinitamente. select()
può anche essere utilizzato per attendere su più di un socket alla volta.
import select
mysocket.setblocking(0)
ready = select.select([mysocket], [], [], timeout_in_seconds)
if ready[0]:
data = mysocket.recv(4096)
Se hai molti descrittori di file aperti, poll () è un'alternativa più efficiente a select()
.
Un'altra opzione è impostare un timeout per tutte le operazioni sul socket utilizzando socket.settimeout()
, ma vedo che hai esplicitamente rifiutato quella soluzione in un'altra risposta.
select
è buono, ma la parte in cui dici "non puoi" è fuorviante, poiché c'è socket.settimeout()
.
select
: se si esegue su una macchina Windows, select
si fa affidamento sulla libreria WinSock, che ha l'abitudine di tornare non appena sono arrivati alcuni dati, ma non necessariamente tutti . Quindi è necessario incorporare un ciclo per continuare a chiamare select.select()
fino a quando non vengono ricevuti tutti i dati. Il modo in cui sai di aver ottenuto tutti i dati spetta (sfortunatamente) a te capirlo: potrebbe significare cercare una stringa di terminazione, un certo numero di byte o semplicemente aspettare un timeout definito.
ready[0]
falso solo se non c'è il corpo nella risposta del server?
select
è preferita quando questa soluzione è una linea (più facile da mantenere, meno rischi nell'implementazione sbagliata) e utilizza la selezione sotto il cofano (l'implementazione è la stessa della risposta @DanielStuzbach).
Come accennato entrambi select.select()
e socket.settimeout()
funzioneranno.
Nota che potresti dover chiamare settimeout
due volte per le tue esigenze, ad es
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()
più di una volta, potresti chiamare il setdefaulttimeout()
metodo in primo luogo.
Il timeout che stai cercando è il timeout del socket di connessione e non quello del socket primario, se implementi il lato server. In altre parole, c'è un altro timeout per l'oggetto socket di connessione, che è l'output di socket.accept()
metodo. Perciò:
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.
Se implementi il lato client, sarebbe semplice.
sock.connect(server_address)
sock.settimeout(3)
Come accennato nelle risposte precedenti, puoi usare qualcosa come: .settimeout()
Ad esempio:
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()
Spero che aiuti!!
È possibile utilizzare socket.settimeout()
che accetta un argomento intero che rappresenta il numero di secondi. Ad esempio, socket.settimeout(1)
imposterà il timeout a 1 secondo
prova questo utilizza il sottostante C.
timeval = struct.pack('ll', 2, 100)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
SO_RCVTIMEO
e SO_SNDTIMEO
.
2
e perché 100
? Qual è il valore di timeout? In quale unità?
timeval = struct.pack('ll', sec, usec)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
usec = 10000 significa 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
Grida a: https://boltons.readthedocs.io/en/latest/socketutils.html
Fornisce un socket bufferizzato, questo fornisce molte funzionalità molto utili come:
.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)