Pour info, si vous choisissez d'utiliser des délais d'expiration ... vous devez savoir comment gérer le délai d'expiration. cette question SO parle de la gestion du délai d'expiration: stackoverflow.com/questions/16745409
Trevor Boyd Smith
Réponses:
126
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.
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.
l'utilisation selectest bonne, mais la partie où vous dites "vous ne pouvez pas" est trompeuse, car il y en a socket.settimeout().
nosklo
1
C'est mieux maintenant, mais je ne vois pas où la réponse a été «explicitement rejetée».
nosklo
7
Une mise en garde sur l'utilisation select- si vous exécutez sur une machine Windows, selects'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.
JDM
4
Pourquoi est-il nécessaire de définir le socket non non bloquant? Je ne pense pas que ce soit important pour l'appel de sélection (et il se bloque jusqu'à ce qu'un descripteur puisse être lu ou que le délai expire dans ce cas) et que recv () ne se bloquera pas si la sélection est satisfaite. Je l'ai essayé en utilisant recvfrom () et il semble fonctionner correctement sans setblocking (0).
HankB
1
Ne ready[0]serait-il faux que s'il n'y a pas de corps dans la réponse du serveur?
Il n'expire pas le recv (du moins quand je l'ai essayé). Seul le accept () a expiré.
Oren S
9
Le socket.recv () semble expirer pour moi très bien après avoir défini socket.settimeout (), exactement comme prévu. Est-ce que j'invente ça? Quelqu'un d'autre peut-il le confirmer?
Aeonaut
3
@Aeonaut Je pense que cela expire la plupart du temps recv (), mais il y a une condition de course. Dans socket.recv (), Python (2.6) appelle select / poll en interne avec le timeout, puis recv () est appelé juste après. Donc, si vous utilisez une socket bloquante et entre ces 2 appels, l'autre point final se bloque, vous pouvez finir par vous suspendre indéfiniment sur recv (). Si vous utilisez un socket non bloquant, python n'appelle pas select.select en interne, donc je pense que la réponse de Daniel Stutzbach est la bonne manière.
emil.p.stanchev
4
En fait, j'ai probablement mal compris lorsque select () revient, alors veuillez gratter le commentaire précédent. Le guide de Beej dit que ce qui précède est un moyen valide d'implémenter un délai d'expiration sur recv: beej.us/guide/bgnet/output/html/singlepage/… donc je vais faire confiance est une source auteur.
emil.p.stanchev
2
Je ne sais pas pourquoi la solution qui utilise selectest 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).
Je pense qu'il entre dans la même chose où je suis, peu importe comment vous piquez et produisez cette fonction, elle se bloque. J'ai essayé 2 ou 4 timeouts maintenant et ça se bloque toujours. Settimeout se bloque également.
Casey Daniel
1
Lorsque vous appelez .settimeout()plus d'une fois, vous pouvez appeler la setdefaulttimeout()méthode en premier lieu.
mvarge
12
Vous pouvez définir un délai avant de recevoir la réponse et après avoir reçu la réponse, le remettre à Aucun:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5.0)
data = sock.recv(1024)
sock.settimeout(None)
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.
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 bytesexcept socket.timeout:# fail after 1 second of no activityprint("Didn't receive data! [Timeout]")finally:
s.close()
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
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)
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'ilrecv()
ne se bloquera jamais indéfiniment.select()
peut également être utilisé pour attendre sur plus d'un socket à la fois.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.la source
select
est bonne, mais la partie où vous dites "vous ne pouvez pas" est trompeuse, car il y en asocket.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 à appelerselect.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()
la source
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()
etsocket.settimeout()
fonctionnera.Notez que vous devrez peut-être appeler
settimeout
deux fois pour vos besoins, par exemplela source
.settimeout()
plus d'une fois, vous pouvez appeler lasetdefaulttimeout()
méthode en premier lieu.Vous pouvez définir un délai avant de recevoir la réponse et après avoir reçu la réponse, le remettre à Aucun:
la source
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:Si vous implémentez le côté client, ce serait simple.
la source
Comme mentionné dans les réponses précédentes, vous pouvez utiliser quelque chose comme:
.settimeout()
Par exemple:J'espère que ça aide!!
la source
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 secondela source
essayez ceci, il utilise le C.
la source
SO_RCVTIMEO
etSO_SNDTIMEO
.2
et pourquoi100
? 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 msla source
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:
la source