使用套接字处理 python 中的多个连接
Handling multiple connections in python with sockets
我有一个代码非常适合一个连接。我已经看到了两个用于多客户端处理的选项,但我并不真正理解。
这是服务器套接字代码:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as listening_sock:
listening_sock.bind(('', port))
listening_sock.listen()
client_soc, client_address = listening_sock.accept()
client_soc.sendall('200#Welcome to my server!'.encode())
print(f'Address {client_soc.getsockname()[0]} connected with port {client_soc.getsockname()[1]}')
while True:
# get message
msg = client_soc.recv(1024).decode()
# receive log print:
print(f'"{msg}" sent from {client_soc.getsockname()[0]}')
if 'Quit' in msg:
client_soc.sendall('200#Thanks for using my server!'.encode())
client_soc.close()
elif '0' < msg.split('#')[0] <= '9': # one of the valid actions
answer = call_action(msg.split('#')[0], db, msg.split('#')[1]) # the answer for given parameter
client_soc.sendall("200#".encode() + answer.encode())
如果我只有一个连接,它运行良好,我需要添加的最后一件事是多客户端处理选项。最短和最简单的方法是什么?
您的代码会自行阻塞。
例如:client_soc, client_address = listening_sock.accept()
接受客户端,然后 while True:
永远运行,因此您只能使用 1 个连接,因为 socket.accept()
被调用一次。您应该学习其中的一些来解决您的问题:asyncio、线程、多处理。这些库将帮助您的代码同时接受客户端并与客户端一起工作。套接字可以使用 every,但通常它们与 asyncio 配对:https://asyncio.readthedocs.io/
代码只调用了一次accept
。相反,在 while 循环中调用 accept
并为每个客户端连接创建一个线程,以便并行处理它们。使用以下模式作为示例:
import socket
import threading
# Thread to handle each "client_soc" connection
def handler(client_soc):
...
client_soc.close()
with socket.socket() as listening_sock:
listening_sock.bind(('', 8000))
listening_sock.listen()
while True:
client_soc, client_address = listening_sock.accept()
# Send each "client_soc" connection as a parameter to a thread.
threading.Thread(target=handler,args=(client_soc,), daemon=True).start()
还有一个内置的套接字服务器可以简化这个过程。这是一个经过测试的示例回显服务器,它回显以换行符终止的数据:
from socketserver import ThreadingTCPServer,StreamRequestHandler
class echohandler(StreamRequestHandler):
def handle(self):
print(f'Connected: {self.client_address[0]}:{self.client_address[1]}')
while True:
# get message
msg = self.rfile.readline()
if not msg:
print(f'Disconnected: {self.client_address[0]}:{self.client_address[1]}')
break # exits handler, framework closes socket
print(f'Received: {msg}')
self.wfile.write(msg)
self.wfile.flush()
server = ThreadingTCPServer(('',8000),echohandler)
server.serve_forever()
我有一个代码非常适合一个连接。我已经看到了两个用于多客户端处理的选项,但我并不真正理解。 这是服务器套接字代码:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as listening_sock:
listening_sock.bind(('', port))
listening_sock.listen()
client_soc, client_address = listening_sock.accept()
client_soc.sendall('200#Welcome to my server!'.encode())
print(f'Address {client_soc.getsockname()[0]} connected with port {client_soc.getsockname()[1]}')
while True:
# get message
msg = client_soc.recv(1024).decode()
# receive log print:
print(f'"{msg}" sent from {client_soc.getsockname()[0]}')
if 'Quit' in msg:
client_soc.sendall('200#Thanks for using my server!'.encode())
client_soc.close()
elif '0' < msg.split('#')[0] <= '9': # one of the valid actions
answer = call_action(msg.split('#')[0], db, msg.split('#')[1]) # the answer for given parameter
client_soc.sendall("200#".encode() + answer.encode())
如果我只有一个连接,它运行良好,我需要添加的最后一件事是多客户端处理选项。最短和最简单的方法是什么?
您的代码会自行阻塞。
例如:client_soc, client_address = listening_sock.accept()
接受客户端,然后 while True:
永远运行,因此您只能使用 1 个连接,因为 socket.accept()
被调用一次。您应该学习其中的一些来解决您的问题:asyncio、线程、多处理。这些库将帮助您的代码同时接受客户端并与客户端一起工作。套接字可以使用 every,但通常它们与 asyncio 配对:https://asyncio.readthedocs.io/
代码只调用了一次accept
。相反,在 while 循环中调用 accept
并为每个客户端连接创建一个线程,以便并行处理它们。使用以下模式作为示例:
import socket
import threading
# Thread to handle each "client_soc" connection
def handler(client_soc):
...
client_soc.close()
with socket.socket() as listening_sock:
listening_sock.bind(('', 8000))
listening_sock.listen()
while True:
client_soc, client_address = listening_sock.accept()
# Send each "client_soc" connection as a parameter to a thread.
threading.Thread(target=handler,args=(client_soc,), daemon=True).start()
还有一个内置的套接字服务器可以简化这个过程。这是一个经过测试的示例回显服务器,它回显以换行符终止的数据:
from socketserver import ThreadingTCPServer,StreamRequestHandler
class echohandler(StreamRequestHandler):
def handle(self):
print(f'Connected: {self.client_address[0]}:{self.client_address[1]}')
while True:
# get message
msg = self.rfile.readline()
if not msg:
print(f'Disconnected: {self.client_address[0]}:{self.client_address[1]}')
break # exits handler, framework closes socket
print(f'Received: {msg}')
self.wfile.write(msg)
self.wfile.flush()
server = ThreadingTCPServer(('',8000),echohandler)
server.serve_forever()