J'ai besoin de définir le délai d'expiration sur la méthode socket recv de python. Comment faire?
J'ai besoin de définir le délai d'expiration sur la méthode socket recv de python. Comment faire?
Réponses:
L'approche typique consiste à utiliser select () pour attendre que les données soient disponibles ou que le délai d'expiration se produise. Appelez uniquement recv()
lorsque les données sont réellement disponibles. Pour être sûr, nous avons également mis le socket en mode non bloquant pour garantir qu'il recv()
ne se bloquera jamais indéfiniment. select()
peut également être utilisé pour attendre sur plus d'un socket à la fois.
import select
mysocket.setblocking(0)
ready = select.select([mysocket], [], [], timeout_in_seconds)
if ready[0]:
data = mysocket.recv(4096)
Si vous avez beaucoup de descripteurs de fichiers ouverts, poll () est une alternative plus efficace à select()
.
Une autre option consiste à définir un délai d'expiration pour toutes les opérations sur le socket à l'aide socket.settimeout()
, mais je vois que vous avez explicitement rejeté cette solution dans une autre réponse.
select
est bonne, mais la partie où vous dites "vous ne pouvez pas" est trompeuse, car il y en a socket.settimeout()
.
select
- si vous exécutez sur une machine Windows, select
s'appuie sur la bibliothèque WinSock, qui a l'habitude de revenir dès que certaines données sont arrivées, mais pas nécessairement toutes . Vous devez donc incorporer une boucle pour continuer à appeler select.select()
jusqu'à ce que toutes les données soient reçues. Il vous appartient (malheureusement) de savoir comment vous savez que vous avez obtenu toutes les données - cela peut signifier rechercher une chaîne de terminaison, un certain nombre d'octets ou simplement attendre un délai d'expiration défini.
ready[0]
serait-il faux que s'il n'y a pas de corps dans la réponse du serveur?
il y a socket.settimeout()
select
est préférée lorsque cette solution est une ligne unique (plus facile à entretenir, moins de risque de mise en œuvre incorrecte) et utilise select sous le capot (la mise en œuvre est la même que la réponse @DanielStuzbach).
Comme mentionné à la fois select.select()
et socket.settimeout()
fonctionnera.
Notez que vous devrez peut-être appeler settimeout
deux fois pour vos besoins, par exemple
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()
plus d'une fois, vous pouvez appeler la setdefaulttimeout()
méthode en premier lieu.
Le délai d'expiration que vous recherchez est le délai d'expiration du socket de connexion et non celui du socket principal, si vous implémentez le côté serveur. En d'autres termes, il existe un autre délai d'expiration pour l'objet socket de connexion, qui est la sortie de socket.accept()
method. Par conséquent:
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.
Si vous implémentez le côté client, ce serait simple.
sock.connect(server_address)
sock.settimeout(3)
Comme mentionné dans les réponses précédentes, vous pouvez utiliser quelque chose comme: .settimeout()
Par exemple:
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()
J'espère que ça aide!!
Vous pouvez utiliser socket.settimeout()
qui accepte un argument entier représentant le nombre de secondes. Par exemple, socket.settimeout(1)
définira le délai d'expiration à 1 seconde
essayez ceci, il utilise le C.
timeval = struct.pack('ll', 2, 100)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
SO_RCVTIMEO
et SO_SNDTIMEO
.
2
et pourquoi 100
? Quelle est la valeur du délai d'expiration? Dans quelle unité?
timeval = struct.pack('ll', sec, usec)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
usec = 10000 signifie 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
Criez à: https://boltons.readthedocs.io/en/latest/socketutils.html
Il fournit un socket tamponné, cela fournit de nombreuses fonctionnalités très utiles telles que:
.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)