python之路 - day29 socketserver模块,实现多线程的 server-client
socketserver模块
使用socketserver模块,在server端,可同时接受多个client连接,并通讯
1.示例一:
基于socketserver模块的框架、基本使用方法
服务端 程序示例:

import socketserver #模块 # 第一步: 自定义一个类,该类继承类:socketserver.BaseRequestHandler class Myserver(socketserver.BaseRequestHandler): def handle(self): # 在类里 定义一个 handle(self)函数,函数名固定,不可更改 ''' 函数体里,编写server端 的业务逻辑代码。当有多个client连接上时,将开启多个线程,分别执行handle函数 :return: ''' while 1: # 针对window系统 try: print("等待信息") data = self.request.recv(1024) # 阻塞 # 针对linux if len(data) == 0: break if data == b'exit': break response = data + b'SB' self.request.send(response) except Exception as e: break self.request.close() # 第二步: 实例化一个对象 ThreadingTCPServer # 该步相当于-------- 1:创建socket对象 2:self.socket.bind() 3:self.socket.listen(5) server=socketserver.ThreadingTCPServer(("127.0.0.1",8899),Myserver) # 第一个参数:封装了IP和Port的元祖 第二个参数: 自定义的类(该类继承类:socketserver.BaseRequestHandler) # 第三步: 调用ThreadingTCPServer对象的.server_forever() 此步的动作,相当于 self.socket.accept() server.serve_forever()
客户端 程序:

import socket sk = socket.socket() sk.connect(('127.0.0.1',8899)) while 1: name = input(">>>>:") sk.send(name.encode('utf-8')) # 字节 response = sk.recv(1024) # 字节 print(response.decode('utf-8'))
拓展: socketserver有以下TCP\UDP 类
- socketserver.ThreadingTCPServer
- socketserver.ThreadingUDPServer
- socketserver.ForkingTCPServer
- socketserver.ForkingUDPServer
2.示例二:
使用socketserver模块 实现功能: 服务端多线程的接收多个客户端上传文件
服务端 程序:

import socketserver class myServer(socketserver.BaseRequestHandler): def handle(self): import struct import socket import json import hashlib print(self.client_address," 上线了!") while 1: # 接收json的打包长度 file_info_length_pack = self.request.recv(4) #接受数据时,使用 self.request.recv(),等同于之前我们使用的conn.recv() file_info_length = struct.unpack("i", file_info_length_pack)[0] # 接收json字符串 file_info_json = self.request.recv(file_info_length).decode("utf8") file_info = json.loads(file_info_json) action = file_info.get("action") filename = file_info.get("filename") filesize = file_info.get("filesize") # 循环接收文件 md5 = hashlib.md5() with open("put/" + filename, "wb") as f: recv_data_length = 0 while recv_data_length < filesize: data = self.request.recv(1024) recv_data_length += len(data) f.write(data) # MD5摘要 md5.update(data) msg = "文件名:{} 文件总大小:{},已成功接收{} 进度:{:.3f}%".format(filename,filesize, recv_data_length, recv_data_length / filesize * 100) print(msg) print(filename," 接收完成!") md5_val = md5.hexdigest() print(md5_val) if md5_val == file_info["md5value"]: # 根据md5算法字符串,判断文件是否一致 print(filename," 文件校验通过!") self.request.send(b"203") else: print(filename,"文件校验失败!") self.request.send(b"204") #实例化一个 scoketserver.ThreadingTCPServer server=socketserver.ThreadingTCPServer(('127.0.0.1',8800),myServer) #接受 客户端连接 res=server.serve_forever()
客户端 程序: (和使用socket模式的写法完全一样)

import socket import os import json import struct import hashlib sock=socket.socket() sock.connect(("127.0.0.1",8800)) while 1 : cmd=input("请输入命令:") # put 111.jpg action,filename=cmd.strip().split(" ") filesize=os.path.getsize(filename) #获取文件大小 file_info={ "action": action, "filename": filename, "filesize": filesize, "md5value":"" } #获取文件的md5字符串 md5_1 = hashlib.md5() # 示例化一个md5对象 with open(filename,"rb") as f: for line in f: md5_1.update(line) file_info["md5value"]=md5_1.hexdigest() #将该字符串发送给server,用于验证接收的文件是否完全和发送时一样 print(md5_1.hexdigest()) file_info_json=json.dumps(file_info).encode("utf8") #将dict用jason处理后,得到jason格式的字符串,再编码成 bytes字节串 ret=struct.pack("i",len(file_info_json)) #使用struct模块,将int转变为长度为4的bytes. # 发送 file_info_json的打包长度 sock.send(ret) # 发送 file_info_json字节串 sock.send(file_info_json) # 发送 文件数据 with open(filename,"rb") as f: for line in f: sock.send(line) is_valid=sock.recv(1024).decode('utf8') if is_valid=="203": print(filename," 文件已成功上传!") else: print(filename,"文件上传失败!")
实现过程,结果如下:
3.socketserver 类继承 示意图