使用 python socketserver 如何将变量传递给处理程序类的构造函数
Posted
技术标签:
【中文标题】使用 python socketserver 如何将变量传递给处理程序类的构造函数【英文标题】:With python socketserver how can I pass a variable to the constructor of the handler class 【发布时间】:2011-10-16 01:52:43 【问题描述】:我想将我的数据库连接传递给 EchoHandler 类,但是我完全不知道该怎么做或访问 EchoHandler 类。
类 EchoHandler(SocketServer.StreamRequestHandler): def 句柄(自我): 打印 self.client_address, '已连接' 如果 __name__ == '__main__': conn = mysqldb.connect (host = "10.0.0.5", user = "user", passwd = "pass", db = "database") SocketServer.ForkingTCPServer.allow_reuse_address = 1 服务器 = SocketServer.ForkingTCPServer(('10.0.0.6', 4242), EchoHandler) print "服务器正在监听 localhost:4242..." 尝试: server.allow_reuse_address server.serve_forever() 除了键盘中断: print "\n保释..."【问题讨论】:
【参考方案1】:不幸的是,实际上没有一种简单的方法可以直接从服务器外部访问处理程序。
您有两个选项可以将信息传递给 EchoHandler 实例:
-
将连接存储为服务器的属性(在调用
server_forever()
之前添加server.conn = conn
),然后通过self.server.conn
访问EchoHandler.handler 中的该属性。
您可以覆盖服务器的finish_request
并在那里分配值(您必须将其传递给 EchoHandler 的构造函数并覆盖 EchoHandler.__init__)。这是一个更加混乱的解决方案,它几乎需要您将连接存储在服务器上。
我的最佳选择:
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
【讨论】:
【参考方案2】:Mark T 在 python 列表存档中有以下要说的内容
在handler类中,self.server指的是服务器对象,所以子类 服务器并覆盖 init 以获取任何其他服务器参数 并将它们存储为实例变量。
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
【讨论】:
为什么不使用super().__init__(...)
而不是MyServer.__init__
?
SocketServer 模块中的类是“旧式”类。必须以这种方式调用超级构造函数。见这里:***.com/questions/11527921/…
@ShivangiSingh 最好发布一个问题。然后我们就可以看到你的代码了。【参考方案3】:
另一种方式,我认为更 Pythonic,是执行以下操作:
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:
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
【讨论】:
【参考方案4】:我目前正在解决同样的问题,但我使用了稍微不同的解决方案,我觉得它稍微好一点,更通用(受@aramaki 启发)。
在EchoHandler
中,您只需覆盖__init__
并指定自定义Creator
方法。
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
然后你可以调用Creator
方法并传递你需要的任何东西。
SocketServer.ForkingTCPServer(('10.0.0.6', 4242), EchoHandler.Creator(0, "foo"))
主要好处是,通过这种方式,您不会创建不必要的实例,并且以更易于管理的方式扩展类 - 您无需再次更改 Creator
方法。
【讨论】:
【参考方案5】:您似乎不能使用ForkingServer
共享变量,因为当进程尝试修改共享变量时会发生写时复制。
把它改成ThreadingServer
,就可以共享全局变量了。
【讨论】:
以上是关于使用 python socketserver 如何将变量传递给处理程序类的构造函数的主要内容,如果未能解决你的问题,请参考以下文章
Python使用socketserver建立一个异步TCP服务器