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

发布于 2024-11-26 21:44:21 字数 648 浏览 6 评论 0原文

我想将数据库连接传递给 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..."

I would like to pass my database connection to the EchoHandler class, however I can't figure out how to do that or access the EchoHandler class at all.


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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

忆沫 2024-12-03 21:44:21

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

您有两种选择来获取 EchoHandler 实例的信息:

  1. 将连接存储为服务器的属性(在调用 server_forever() 之前添加 server.conn = conn)以及然后通过 self.server.conn 访问 EchoHandler.handler 中的该属性。
  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

Unfortunately, there really isn't an easy way to access the handlers directly from outside the server.

You have two options to get the information to the EchoHandler instances:

  1. Store the connection as a property of the server (add server.conn = conn before calling server_forever()) and then access that property in EchoHandler.handler through self.server.conn.
  2. You can overwrite the server's finish_request and assign the value there (you would have to pass it to the constructor of EchoHandler and overwrite EchoHandler.__init__). That is a far messier solution and it pretty much requires you to store the connection on the server anyway.

My optionon of your best bet:

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
苏大泽ㄣ 2024-12-03 21:44:21

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

在 handler 类中, self.server 指的是服务器对象,所以 subclass
服务器并覆盖 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

Mark T has the following to say on the python list archive

In the handler class, self.server refers to the server object, so subclass
the server and override init to take any additional server parameters
and store them as instance variables.


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

甜点 2024-12-03 21:44:21

我认为更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

Another way, that I believe more pythonic, is to do the following:

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)

You can now give an instance of your handler to the TCPServer:

SocketServer.ForkingTCPServer(('10.0.0.6', 4242), EchoHandler("aaa", "bbb"))

The TCPServer normally creates a new instance of EchoHandler per request but in this case, the __call__ method will be called instead of the constructor (it is already an instance.)

In the call method, I explicitly make a copy of the current EchoHandler and pass it to the super constructor to conform to the original logic of "one handler instance per request".

It is worth having a look at the SocketServer module to understand what happens here: https://github.com/python/cpython/blob/2.7/Lib/SocketServer.py

遥远的绿洲 2024-12-03 21:44:21

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

I was currently solving same problem, but I used slightly different solution, I feel it's slightly nicer and more general (inspired by @aramaki).

In the EchoHandler you just need to overwrite __init__ and specify custom Creator method.

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

Then you can just call the Creator method and pass anything you need.

SocketServer.ForkingTCPServer(('10.0.0.6', 4242), EchoHandler.Creator(0, "foo"))

Main benefit is, that this way you are not creating any more instances than necessary and you are extending the class in more manageable way - you don't need to change the Creator method ever again.

失而复得 2024-12-03 21:44:21

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

It seems that you can't use ForkingServer to share variables because Copy-on-Write happens when a process tries to modify a shared variable.
Change it to ThreadingServer and you'll be able to share global variables.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文