使用 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服务器

Python使用socketServer包搭建简易服务器过程详解

Python基础:网络编程socketserver高级篇

python基础 socketserver

Python SocketServer:发送到多个客户端?

Python 套接字socketserver网络编程