Python TCPServer 多线程多客户端通信的实现
本文详细介绍Python中基于socketserver模块实现TCPServer多线程多客户端通信的方法。通过继承ThreadingMixIn和StreamRequestHandler,服务器可同时处理多个客户端连接。此外,提供了客户端自动重连机制的代码示例,确保网络异常时能恢复连接,适用于需要高并发和稳定性的网络应用开发场景。
原始TCP通信Demo
本节展示最简单、原始的TCP通信Demo。
以下是服务端的HTTP请求处理代码示例:
import socket
# 创建一个servicesocke
serviceSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 给服务器绑定地址(ip地址,端口号)
serviceSocket.bind(("192.168.171.1", 80))
print("等待客户端接入")
# sock 是客户端的socket信息
# addr 是客户端的地址(ip,端口)
sock, addr = serviceSocket.accept()
print(f"sock from client:{sock}")
print(f"addr of client:{addr}")
while True:
# 接收客户端的请求
recvData = sock.recv(1024)
print("客户端说:%s" % (recvData.decode("utf-8")))
sendData = input("服务器说:")
# 发送(回复)数据给客户端
sock.send(sendData.encode("utf-8"))
以下是客户端的HTTP请求处理代码示例:
import socket
# 创建客户端socket
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
clientSocket.connect(("192.168.171.1", 80))
while True:
# 发送消息给服务器
sendData = input("客户端说:")
if sendData == "bye":
clientSocket.send(sendData.encode("utf-8")) # 编码:将数据装换成二进制形式
break
clientSocket.send(sendData.encode("utf-8"))
recvData = clientSocket.recv(1024)
print("服务器说:%s" % (recvData.decode("utf-8"))) # 解码:将二进制转换成字符
TCP客户端与服务端实现流程
在TCP通信中,客户端的实现流程主要包含以下步骤:
首先创建客户端的socket对象以建立与服务器之间的联系,随后发送请求并接收数据,最后关闭连接。
服务端的实现流程则包括:
创建服务端的socket对象,绑定服务端的地址,设置监听器以等待客户端的连接。一旦接收到客户端的请求,服务端将接收请求并返回处理结果到客户端。
多线程多客户端通信与自动重连实现
接下来展示使用ThreadingTCPServer实现的多线程多客户端通信及自动重连的Demo。
以下是socketserver的继承关系图:

图中展示了TCPServer的相关类结构。
# from socketserver import TCPServer, BaseRequestHandler, ThreadingTCPServer
from socketserver import TCPServer, StreamRequestHandler, ThreadingMixIn
import traceback
# class MyBaseRequestHandler(BaseRequestHandler):
class MyBaseRequestHandler(StreamRequestHandler):
def handle(self):
self.addr = self.request.getpeername()
self.server.users[self.addr[1]] = self.request
message = "IP " + self.addr[0] + ":" + str(self.addr[1]) + " Connected..."
print(message)
while True:
try:
data = self.request.recv(1024).decode('UTF-8', 'ignore').strip()
print(f'receive from {self.client_address}:{data}')
back_data = (f"response\"" + data + "\":\n").encode("utf8")
self.request.sendall(back_data)
except:
traceback.print_exc()
break
# 源码:class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
# 从ThreadingMixIn和TCPServer继承,实现多线程
class MyThreadingTCPServer(ThreadingMixIn, TCPServer):
def __init__(self, server_address, RequestHandlerClass):
TCPServer.__init__(self, server_address, RequestHandlerClass)
self.users = {}
class MyTCPserver():
def __init__(self, server_addr='192.168.1.109', server_port=23):
self.server_address = server_addr
self.server_port = server_port
self.server_tuple = (self.server_address, self.server_port)
def run(self):
# server = TCPServer(self.server_tuple, MyBaseRequestHandler)
server = MyThreadingTCPServer(self.server_tuple, MyBaseRequestHandler)
server.serve_forever()
if __name__ == '__main__':
myserver = MyTCPserver()
myserver.run()
在telnet环境下开启两个客户端,本电脑的IP为192.168.1.109。开启两个客户端后,TCPServer的终端会出现同一个IP但不同端口的连接记录。

这是TCPClient的连接状态示意。
import socket
import time
class MyClient:
host = '192.168.1.109'
port = 23
bufsiz = 1024
addr = None
skt = None
def __init__(self, host=None, port=None):
if host != None:
self.host = host
if port != None:
self.port = port
if self.addr == None:
self.addr = (self.host, self.port)
self.doConnection()
def doConnection(self):
try:
self.skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.skt.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
print(self.addr)
self.skt.connect(self.addr)
except:
pass
def run(self):
while True:
try:
_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.skt.sendall(f'{_time}:i am clent1 '.encode('utf-8'))
data = self.skt.recv(self.bufsiz)
print(data.decode('utf-8', 'ignore'))
if not data:
break
print(data.strip())
time.sleep(5)
except socket.error:
print('socket error, reconnection') # 自动重连
time.sleep(3)
self.doConnection()
except:
print('other error')
self.skt.close()
myclient = MyClient()
myclient.run()
上述示例使用telnet工具作为客户端,这里改用代码实现模拟的客户端。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













