HOWTO · Python
OSError: [WinError 10038] Es wurde eine Operation für etwas versucht, das kein Socket ist
Mit dieser Erklärung lernen wir, was Server und Client sind und wie man das Socket-Modul verwendet, um eine Anwendung mit Hilfe von Server und Client zu erstellen. Wir werden auch lernen, wie man Fehler vermeidet, wenn man diese Art von Anwendungen in Python erstellt.
Auf dieser Seite
OSError: [WinError 10038] bedeutet, dass eine Operation mit etwas ausgeführt werden sollte, das kein aktiver Socket ist. Im fehlerhaften Servermuster unten wird der angenommene Client-Socket geschlossen und anschließend in einer inneren Schleife erneut verwendet. Bearbeiten Sie jede Verbindung einmal und kehren Sie dann zu accept() zurück, um den nächsten Client anzunehmen.
Ein minimales Python-Client-Server-Socket-Beispiel erstellen
Ein Server nimmt Verbindungen über einen lauschenden Socket entgegen. Wenn accept() zurückkehrt, erhält der Server einen neuen, verbundenen Socket für diesen Client; der lauschende Socket bleibt für spätere Verbindungen verfügbar. Der Client erstellt seinen eigenen Socket und ruft connect() mit derselben Adresse und demselben Port auf.
Speichern Sie den Code als socket_demo.py. Ohne Argument startet das Skript einen Server-Thread und einen Client für eine kurze lokale Demonstration. Mit den Modi server und client können Sie die Endpunkte auch als getrennte Prozesse ausführen.
import socket
import sys
import threading
HOST = "127.0.0.1"
PORT = 6060
MESSAGE = b"Welcome to the server!"
def serve(ready=None):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as listener:
listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listener.bind((HOST, PORT))
listener.listen(1)
if ready is not None:
ready.set()
connection, address = listener.accept()
with connection:
print(f"Connected: {address[0]}")
connection.sendall(MESSAGE)
def receive():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
client.connect((HOST, PORT))
chunks = []
while True:
chunk = client.recv(2048)
if not chunk:
break
chunks.append(chunk)
message = b"".join(chunks)
print(message.decode("utf-8"))
if len(sys.argv) > 1 and sys.argv[1] == "server":
serve()
elif len(sys.argv) > 1 and sys.argv[1] == "client":
receive()
else:
ready = threading.Event()
server = threading.Thread(target=serve, args=(ready,))
server.start()
ready.wait()
receive()
server.join()
Connected: 127.0.0.1
Welcome to the server!
Der Client sammelt Daten in Blöcken, bis der Server die angenommene Verbindung schließt, und fügt die Bytes anschließend zusammen, bevor er sie dekodiert. So lässt sich eine Nachricht verarbeiten, die über mehrere TCP-Lesevorgänge hinweg eintrifft. Für getrennte Prozesse öffnen Sie zwei Terminals in dem Verzeichnis, in dem die Datei liegt. Führen Sie im ersten Terminal python socket_demo.py server aus; der Server wartet dann auf einen Client. Starten Sie anschließend im zweiten Terminal python socket_demo.py client. Der Server gibt die Loopback-Adresse des Clients aus, der Client die empfangene Nachricht. Nach dem Senden schließt der Server diese Verbindung. Der lauschende Socket wird geschlossen, wenn dieses Beispiel mit einer einzelnen Verbindung endet.
OSError: [WinError 10038] diagnostizieren und beheben
Im fehlerhaften Muster ruft die äußere Schleife accept() auf und speichert den verbundenen Socket in Client_Socket. Die innere Schleife while True sendet einmal und schließt diesen Socket. Beim nächsten Durchlauf versucht sie, erneut über denselben geschlossenen Socket zu senden. Dabei kann OSError: [WinError 10038] auftreten. Die innere Schleife ruft accept() nicht auf. Da sie nie endet, kann die äußere Schleife keinen weiteren Client annehmen.
Entfernen Sie zur Behebung die bedingungslose innere Schleife und bearbeiten Sie in jedem Durchlauf der äußeren Schleife genau eine angenommene Verbindung: Verbindung annehmen, Daten senden und anschließend den verbundenen Socket schließen. Lassen Sie den lauschenden Socket geöffnet, solange der Server weitere Clients annehmen soll. Das Schließen des angenommenen Sockets schließt den lauschenden Socket nicht. Auch das Ausführen der Dateien in einem Terminal verursacht diesen Fehler nicht.
Suchen Sie bei der Diagnose im eigenen Code den Socket, den die fehlschlagende Operation verwendet. Prüfen Sie, ob genau dieser Socket bereits geschlossen wurde, und stellen Sie sicher, dass jede angenommene Verbindung einmal bearbeitet wird. Bei einem echten Dienst sollte die Annahmeschleife des Servers weiterlaufen und die Bearbeitung einzelner Clients an einen Handler übergeben werden. Dieses Beispiel bearbeitet absichtlich einen Client und wird dann beendet.