如何向Python的TCPServer Handler类传递参数?
向socketserver的Handler传递文件名参数的合理方案
原代码实现了客户端读取文件内容发送到TCP服务端,服务端打印接收数据的功能。现在要把服务端的打印逻辑改成写入文件,又不想用硬编码或全局变量,下面是几个靠谱的实现方案:
方案1:利用TCPServer的自定义属性传递参数
TCPServer的构造函数会把额外的关键字参数绑定到自身实例上,Handler类可以通过self.server访问到服务端实例,进而拿到传递的参数。
修改后的完整代码:
from socket import socket, AF_INET, SOCK_STREAM from socketserver import BaseRequestHandler, TCPServer from threading import Thread HOST = "localhost" PORT = 10101 ADDR = HOST, PORT RECVBUF = 4096 SENDBUF = RECVBUF // 2 INPFILE = "inputfile.txt" OUTPUTFILE = "outputfile.txt" # 目标输出文件 class MyHandler(BaseRequestHandler): def handle(self): # 从服务端实例中获取输出文件名 with open(self.server.output_file, "ab") as outfile: while data := self.request.recv(RECVBUF): outfile.write(data) def server(tcpserver: TCPServer): tcpserver.serve_forever() if __name__ == "__main__": with open(INPFILE, "rb") as indata: # 初始化TCPServer时传入自定义属性output_file with TCPServer(ADDR, MyHandler, output_file=OUTPUTFILE) as tcpserver: (t := Thread(target=server, args=[tcpserver])).start() with socket(AF_INET, SOCK_STREAM) as s: s.connect(ADDR) while chunk := indata.read(SENDBUF): s.sendall(chunk) tcpserver.shutdown() t.join()
方案2:用工厂函数动态生成带参数的Handler类
写一个工厂函数,接收文件名参数后,返回一个已经绑定该参数的Handler子类,利用闭包特性让内部类能访问到外部参数。
修改后的完整代码:
from socket import socket, AF_INET, SOCK_STREAM from socketserver import BaseRequestHandler, TCPServer from threading import Thread HOST = "localhost" PORT = 10101 ADDR = HOST, PORT RECVBUF = 4096 SENDBUF = RECVBUF // 2 INPFILE = "inputfile.txt" OUTPUTFILE = "outputfile.txt" def create_handler(output_file): class CustomHandler(BaseRequestHandler): def handle(self): with open(output_file, "ab") as outfile: while data := self.request.recv(RECVBUF): outfile.write(data) return CustomHandler def server(tcpserver: TCPServer): tcpserver.serve_forever() if __name__ == "__main__": with open(INPFILE, "rb") as indata: # 通过工厂函数创建带参数的Handler类 MyHandler = create_handler(OUTPUTFILE) with TCPServer(ADDR, MyHandler) as tcpserver: (t := Thread(target=server, args=[tcpserver])).start() with socket(AF_INET, SOCK_STREAM) as s: s.connect(ADDR) while chunk := indata.read(SENDBUF): s.sendall(chunk) tcpserver.shutdown() t.join()
方案3:自定义TCPServer子类封装参数
如果需要传递多个参数或者要扩展服务端功能,自定义TCPServer子类,把参数封装在子类属性中,Handler同样通过self.server访问。
修改后的完整代码:
from socket import socket, AF_INET, SOCK_STREAM from socketserver import BaseRequestHandler, TCPServer from threading import Thread HOST = "localhost" PORT = 10101 ADDR = HOST, PORT RECVBUF = 4096 SENDBUF = RECVBUF // 2 INPFILE = "inputfile.txt" OUTPUTFILE = "outputfile.txt" class CustomTCPServer(TCPServer): def __init__(self, server_address, RequestHandlerClass, output_file, bind_and_activate=True): self.output_file = output_file super().__init__(server_address, RequestHandlerClass, bind_and_activate) class MyHandler(BaseRequestHandler): def handle(self): with open(self.server.output_file, "ab") as outfile: while data := self.request.recv(RECVBUF): outfile.write(data) def server(tcpserver: CustomTCPServer): tcpserver.serve_forever() if __name__ == "__main__": with open(INPFILE, "rb") as indata: with CustomTCPServer(ADDR, MyHandler, OUTPUTFILE) as tcpserver: (t := Thread(target=server, args=[tcpserver])).start() with socket(AF_INET, SOCK_STREAM) as s: s.connect(ADDR) while chunk := indata.read(SENDBUF): s.sendall(chunk) tcpserver.shutdown() t.join()
内容的提问来源于stack exchange,提问作者jackal
相关产品推荐
相关产品推荐

