With python socketserver how can I pass a variable to the constructor of the handler class
我想将我的数据库连接传递给EchoHandler类,但我根本无法弄清楚如何执行此操作或访问EchoHandler类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class EchoHandler(SocketServer.StreamRequestHandler): def handle(self): print self.client_address, 'connected' if __name__ == '__main__': conn = MySQLdb.connect (host ="10.0.0.5", user ="user", passwd ="pass", db ="database") SocketServer.ForkingTCPServer.allow_reuse_address = 1 server = SocketServer.ForkingTCPServer(('10.0.0.6', 4242), EchoHandler) print"Server listening on localhost:4242..." try: server.allow_reuse_address server.serve_forever() except KeyboardInterrupt: print" bailing..." |
不幸的是,实际上没有一种简单的方法可以直接从服务器外部访问处理程序。
您有两种方法可以获取EchoHandler实例的信息:
我最喜欢的选择:
1 2 3 4 5 6 7 8 9 10 11 12 13 | class EchoHandler(SocketServer.StreamRequestHandler): def handle(self): # I have no idea why you would print this but this is an example print( self.server.conn ); print self.client_address, 'connected' if __name__ == '__main__': SocketServer.ForkingTCPServer.allow_reuse_address = 1 server = SocketServer.ForkingTCPServer(('10.0.0.6', 4242), EchoHandler) server.conn = MySQLdb.connect (host ="10.0.0.5", user ="user", passwd ="pass", db ="database") # continue as normal |
Mark T在python列表存档上有以下说法
在处理程序类中,self.server引用服务器对象,因此是子类
服务器和覆盖init以获取任何其他服务器参数
并将它们存储为实例变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import SocketServer class MyServer(SocketServer.ThreadingTCPServer): def __init__(self, server_address, RequestHandlerClass, arg1, arg2): SocketServer.ThreadingTCPServer.__init__(self, server_address, RequestHandlerClass) self.arg1 = arg1 self.arg2 = arg2 class MyHandler(SocketServer.StreamRequestHandler): def handle(self): print self.server.arg1 print self.server.arg2 |
我相信更多pythonic的另一种方法是执行以下操作:
1 2 3 4 5 6 7 8 | class EchoHandler(SocketServer.StreamRequestHandler): def __init__(self, a, b): self.a = a self.b = b def __call__(self, request, client_address, server): h = EchoHandler(self.a, self.b) SocketServer.StreamRequestHandler.__init__(h, request, client_address, server) |
您现在可以将处理程序的实例提供给TCPServer:
1 | SocketServer.ForkingTCPServer(('10.0.0.6', 4242), EchoHandler("aaa","bbb")) |
TCPServer通常会为每个请求创建一个新的EchoHandler实例,但在这种情况下,将调用__call__方法而不是构造函数(它已经是一个实例。)
在call方法中,我显式地创建了当前EchoHandler的副本,并将其传递给超级构造函数,以符合"每个请求一个处理程序实例"的原始逻辑。
值得一看的是SocketServer模块,以了解这里发生的事情:https://github.com/python/cpython/blob/2.7/Lib/SocketServer.py
我目前正在解决同样的问题,但我使用了稍微不同的解决方案,我觉得它更好一点,更一般(受@aramaki启发)。
在
1 2 3 4 5 6 7 8 9 10 11 12 13 | class EchoHandler(SocketServer.StreamRequestHandler): def __init__(self, request, client_address, server, a, b): self.a = a self.b = b # super().__init__() must be called at the end # because it's immediately calling handle method super().__init__(request, client_address, server) @classmethod def Creator(cls, *args, **kwargs): def _HandlerCreator(request, client_address, server): cls(request, client_address, server, *args, **kwargs) return _HandlerCreator |
然后你可以调用
1 | SocketServer.ForkingTCPServer(('10.0.0.6', 4242), EchoHandler.Creator(0,"foo")) |
主要的好处是,通过这种方式,您不会创建任何超出必要的实例,而是以更易于管理的方式扩展类 - 您无需再次更改