24

我想将我的数据库连接传递给 EchoHandler 类,但是我根本不知道如何做到这一点或访问 EchoHandler 类。

类 EchoHandler(SocketServer.StreamRequestHandler):
    def 句柄(自我):
        打印 self.client_address, 'connected'

如果 __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 "服务器正在监听 localhost:4242..."
    尝试:
        server.allow_reuse_address
        server.serve_forever()
    除了键盘中断:
        print "\n保释..."
4

5 回答 5

31

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

您有两个选项来获取 EchoHandler 实例的信息:

  1. 将连接存储为服务器的属性(server.conn = conn在调用之前添加server_forever()),然后通过 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
于 2011-07-29T15:58:17.480 回答
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

于 2013-01-03T04:47:24.373 回答
1

另一种方法,我认为更 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__方法而不是构造函数(它已经是一个实例。)

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

值得看看 SocketServer 模块来了解这里发生了什么:https ://github.com/python/cpython/blob/2.7/Lib/SocketServer.py

于 2017-07-21T09:15:20.863 回答
1

我目前正在解决同样的问题,但我使用了稍微不同的解决方案,我觉得它更好更通用(受@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再次更改方法。

于 2018-11-06T19:08:05.550 回答
1

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

于 2021-07-22T18:39:17.773 回答