Я создаю два простых скрипта Python для сервера-клиента, которые отображают команды.То есть сервер открывает сокет, затем клиент подключается, отправляет простое сообщение, затем сервер возвращает сообщение обратно клиенту, который затем печатает его.Я пытаюсь сделать это многопоточным, и вот здесь возникает проблема.
Я следую этому Real Python учебнику, и смогуспешно запустите echo-client.py и echo-server.py .Я понимаю основную концепцию и могу просто следовать коду.Поэтому я добавил код в серверную программу, чтобы сделать его многопоточным:
server-multithreaded.py
#!/usr/bin/env python3
import socket
from threading import Thread
HOST = "127.0.0.1"
PORT = 65432
BUFFER_SIZE = 16
def handler(conn, addr):
while True:
data = conn.recv(BUFFER_SIZE)
print(f"Server received {len(data)} bytes from {addr[0]}")
if not data:
break
conn.sendall(data)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
print(f"Connection from {addr[0]}")
Thread(target=handler, args=(conn, addr)).start()
И вот клиентская программа.
client.py
#!/usr/bin/env python3
import socket
HOST = "127.0.0.1"
PORT = 65432
BUFFER_SIZE = 16
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
s.sendall(b"Hello, world!")
data = s.recv(BUFFER_SIZE)
print(f"Received {data}")
Когда я запускаю многопоточный сервер, я получаю следующую трассировку:
Connection from 127.0.0.1
Server received 13 bytes from 127.0.0.1
Exception in thread Thread-1:
Traceback (most recent call last):
File "D:\Program Files\Python\Python37\lib\threading.py", line 917, in _bootstrap_inner
self.run()
File "D:\Program Files\Python\Python37\lib\threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "server-multithreaded-new.py", line 17, in handler
conn.sendall(data)
OSError: [WinError 10038] An operation was attempted on something that is not a socket
Кроме того, клиент не получает полный текст «Hello, World!»обратное сообщение (как в не многопоточной версии).Вместо этого он просто получает пустую байтовую строку:
Received b''
Я предполагаю, что каким-то образом сокет, кажется, закрывается, пока данные все еще передаются, но я не знаю почему.В конце концов, я понимаю, что менеджер контекста with
должен обрабатывать закрытие разумно и автоматически.
Кто-нибудь знает, почему это происходит, и как я могу это исправить?