使用python socketserver如何将变量传递给处理程序类的构造函数

时间:2011-07-29 15:41:36

标签: python python-2.7 socketserver

我想将我的数据库连接传递给EchoHandler类,但我根本无法弄清楚如何操作或访问EchoHandler类。


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 "\nbailing..."

5 个答案:

答案 0 :(得分:25)

不幸的是,实际上没有一种简单的方法可以直接从服务器外部访问处理程序。

您有两种方法可以获取EchoHandler实例的信息:

  1. 将连接存储为服务器的属性(在调用server.conn = conn之前添加server_forever()),然后通过self.server.conn在EchoHandler.handler中访问该属性。
  2. 您可以覆盖服务器的finish_request并在那里分配值(您必须将其传递给EchoHandler的构造函数并覆盖EchoHandler .__ init__)。这是一个 更混乱的 解决方案,它几乎要求您将连接存储在服务器上。
  3. 我最喜欢的选择:

    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
    

答案 1 :(得分:9)

Mark T在python list archive上有以下说法

在处理程序类中,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

答案 2 :(得分:1)

另一种方式,我相信更多的pythonic,是做以下事情:

^

您现在可以将处理程序的实例提供给TCPServer:

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通常会为每个请求创建一个新的 EchoHandler 实例,但在这种情况下,将调用 __ call __ 方法而不是构造函数(它已经是一个实例。 )

调用方法中,我显式创建了当前EchoHandler的副本,并将其传递给超级构造函数,以符合“每个请求一个处理程序实例”的原始逻辑。

值得一看的是SocketServer模块,以了解这里发生的事情:https://github.com/python/cpython/blob/2.7/Lib/SocketServer.py

答案 3 :(得分:1)

似乎您不能使用 ForkingServer 来共享变量,因为当进程尝试修改共享变量时会发生写时复制。 将其更改为 ThreadingServer,您将能够共享全局变量。

答案 4 :(得分:0)

我目前正在解决相同的问题,但是我使用的解决方案略有不同,我觉得它更好一些,也更通用(受@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方法。