如何在python socketserver中将变量传递给处理类的构造函数?

26 投票
5 回答
14437 浏览
提问于 2025-04-16 22:31

我想把我的数据库连接传递给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 个回答

1

另一种我认为更符合Python风格的方法是这样做:

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

11

Mark T 在 Python 列表的讨论中提到:

在处理类里,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

33

很遗憾,从服务器外部直接访问处理程序并没有简单的方法。

你有两种选择可以将信息传递给 EchoHandler 实例:

  1. 把连接存储为服务器的一个属性(在调用 server_forever() 之前加上 server.conn = conn),然后在 EchoHandler.handler 中通过 self.server.conn 来访问这个属性。
  2. 你可以重写服务器的 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

撰写回答