Comprendre le comportement des sockets : pourquoi Socket.recv() se bloque sans données envoyées
Les sockets Python, comme les connexions TCP, se comportent comme des flux de données qui circulent entre les clients et les serveurs. Cet article examine les raisons du problème selon lequel un appel socket.recv() ne parvient pas à renvoyer des données après la modification de la transmission des données.
L'exemple du serveur Echo
Considérez l'exemple du serveur d'écho Python de la documentation officielle. Ce serveur écoute les connexions entrantes, reçoit les données et les renvoie au client. L'extrait de code suivant reproduit le comportement d'origine du serveur :
import socket HOST = '' PORT = 50007 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((HOST, PORT)) s.listen(1) conn, addr = s.accept() print('Connected by', addr) while True: data = conn.recv(1024) if not data: break conn.sendall(data) conn.close()
Modification du comportement du serveur
Le problème survient lorsque le code est modifié pour ne pas renvoyer de données au client. :
while True: data = conn.recv(1024) if not data: break conn.close()
Dans ce code modifié, la boucle while reçoit sans cesse des données du client, mais le serveur n'envoie jamais de données dos. Cela provoque le blocage du client indéfiniment lors de l'appel socket.recv().
Comprendre le flux de communication
Les sockets TCP ne maintiennent pas une relation un-à-un entre l'envoi et la réception d'appels sur différents points de terminaison. Au lieu de cela, le protocole définit les règles de communication. Dans ce cas, le serveur d'écho d'origine a implémenté une règle selon laquelle le serveur renvoie les données reçues jusqu'à ce que le client ferme la connexion.
Lorsque le comportement du serveur est modifié, les règles ont effectivement été modifiées. Le serveur ne reçoit désormais que les données et les supprime jusqu'à ce que le client ferme la connexion. Le serveur ne renvoie jamais de données au client.
Adaptation du comportement du client
Pour travailler avec le serveur modifié, le client doit ajuster son comportement. Étant donné que le serveur n'envoie plus de données activement, le client suppose que la réception des données indique une connexion terminée. Pour faciliter cela, le client doit fermer son côté sortant de la connexion pour signaler au serveur qu'il a fini d'envoyer des données. Le client peut ensuite effectuer plusieurs appels recv pour gérer toute fragmentation potentielle des données entrantes.
Code mis à jour
Vous trouverez ci-dessous le code mis à jour pour le serveur et le client qui adhère aux règles modifiées de communication :
Serveur :
import socket HOST = '' PORT = 50007 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((HOST, PORT)) s.listen(1) conn, addr = s.accept() print('Connected by', addr) while True: data = conn.recv(1024) if not data: break conn.sendall(b'ok') conn.shutdown(socket.SHUT_WR) conn.close()
Client :
import socket HOST = 'localhost' PORT = 50007 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) s.sendall(b'Hello, world') s.shutdown(socket.SHUT_WR) data = b'' while True: buf = s.recv(1024) if not buf: break data += buf s.close() print('Received', repr(data))
En comprenant la nature basée sur les flux de Sockets TCP et en ajustant les règles de communication en conséquence, il est possible de résoudre le problème où socket.recv() se bloque sans que les données ne soient envoyées.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!