Socket-Verhalten verstehen: Warum Socket.recv() ohne gesendete Daten blockiert
Python-Sockets verhalten sich wie TCP-Verbindungen wie Datenströme die zwischen Clients und Servern fließen. In diesem Artikel werden die Gründe für das Problem erläutert, bei dem ein socket.recv()-Aufruf keine Daten zurückgibt, nachdem die Datenübertragung geändert wurde.
Das Echo-Server-Beispiel
Betrachten Sie das Python-Echoserver-Beispiel aus der offiziellen Dokumentation. Dieser Server lauscht auf eingehende Verbindungen, empfängt Daten und sendet sie an den Client zurück. Der folgende Codeausschnitt reproduziert das ursprüngliche Serververhalten:
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()
Änderung des Serververhaltens
Das Problem tritt auf, wenn der Code so geändert wird, dass keine Daten an den Client zurückgesendet werden :
while True: data = conn.recv(1024) if not data: break conn.close()
In diesem modifizierten Code empfängt die while-Schleife endlos Daten vom Client, aber der Server sendet niemals Daten zurück. Dies führt dazu, dass der Client beim Aufruf von socket.recv() auf unbestimmte Zeit blockiert.
Den Kommunikationsfluss verstehen
TCP-Sockets pflegen keine Eins-zu-eins-Beziehung zwischen dem Senden und Empfangen von Anrufen an verschiedenen Endpunkten. Stattdessen definiert das Protokoll die Regeln für die Kommunikation. In diesem Fall hat der ursprüngliche Echo-Server eine Regel implementiert, nach der der Server die empfangenen Daten zurückgibt, bis der Client die Verbindung schließt.
Wenn das Serververhalten geändert wird, wurden die Regeln effektiv geändert. Der Server empfängt nun nur noch Daten und verwirft diese, bis der Client die Verbindung schließt. Der Server sendet niemals Daten zurück an den Client.
Anpassen des Client-Verhaltens
Um mit dem geänderten Server arbeiten zu können, muss der Client sein Verhalten anpassen. Da der Server keine Daten mehr aktiv sendet, geht der Client davon aus, dass der Empfang von Daten auf eine abgeschlossene Verbindung hinweist. Um dies zu erleichtern, sollte der Client seine ausgehende Seite der Verbindung schließen, um dem Server zu signalisieren, dass er mit dem Senden der Daten fertig ist. Der Client kann dann mehrere recv-Aufrufe ausführen, um eine mögliche Fragmentierung der eingehenden Daten zu bewältigen.
Aktualisierter Code
Unten finden Sie aktualisierten Code sowohl für den Server als auch für den Client hält sich an die geänderten Regeln von Kommunikation:
Server:
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))
Durch das Verständnis der Stream-basierten Natur von TCP-Sockets und die entsprechende Anpassung der Kommunikationsregeln können das Problem beheben, bei dem socket.recv() ins Stocken gerät, ohne dass Daten gesendet werden.
Das obige ist der detaillierte Inhalt vonWarum bleibt „socket.recv()' stehen, wenn der Server keine Daten zurücksendet?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!