在python TCP Server中为handle()添加功能的正确方法?

时间:2011-03-30 00:11:12

标签: python

我有这样的代码:

class SingleTCPHandler(SocketServer.BaseRequestHandler):
    """ One instance per connection. """
    def handle(self):
        data = Net.recv_from_socket(self.request)
        GUI.run(str("RECV'd message: %s" % data))

class SimpleServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    def __init__(self, server_address, RequestHandlerClass):
        SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass)

但我不想使用全局变量GUI来包含我的服务器收到消息时要调用的函数。相反,我想向SingleTCPHandler类发送GUI对象,以便它可以在本地调用函数,而不是引用全局变量。

思考?蟒蛇新手......

3 个答案:

答案 0 :(得分:7)

将处理程序更改为

class SingleTCPHandler(SocketServer.BaseRequestHandler):
    """ One instance per connection. """
    def __init__(self, callback, *args, **keys):
        self.callback = callback
        SocketServer.BaseRequestHandler.__init__(self, *args, **keys)

    def handle(self):
        data = Net.recv_from_socket(self.request)
        self.callback(data)

稍后(创建TCP服务器的地方):

def show_message_box(data):
    GUI.run(str("RECV'd message: %s" % data))
def handler_factory(callback):
    def createHandler(*args, **keys):
        return ThreadedTCPRequestHandler(callback, *args, **keys)
    return createHandler
server = ThreadedTCPServer((HOST, PORT), handler_factory(show_message_box))

说明:

1)使用应该调用的回调调用handler_factory。

2)handler_factory创建一个名为createHandler的新函数。此函数将移交给ThreadedTCPServer。它在需要创建新处理程序时调用它。

3)调用时,它会创建ThreadedTCPRequestHandler并将回调参数(在此示例中为show_message_box)移交给存储它的Th​​readedTCPRequestHandler。 init 。这背后的“神奇”被称为“封闭”。即您可以从内部函数createHandler中的外部函数handler_factory访问回调参数。谷歌的“关闭python”,你会得到一些很好的解释。

4)当最后调用handle()时,它调用self.callback(data)。由于self.callback是show_message_box,因此将有效地调用show_message_box(data)。

表达这一点的方式略短:

def my_callback():
    print 'Hello'
server = ThreadedTCPServer((HOST, PORT), lambda *args, **keys: ThreadedTCPRequestHandler(my_callback, *args, **keys))

将起作用,就像

一样
def my_callback():
    print 'Hello'
import functools
server = ThreadedTCPServer((HOST, PORT), functools.partial(ThreadedTCPRequestHandler, my_callback))

我不知道你的具体用例,但如果你需要用套接字做更多的东西,你可能想看看http://www.twistedmatrix.com(流行的python网络包)。您还应该知道许多GUI系统不喜欢从多个线程同时运行,因此您需要注意这一点。

答案 1 :(得分:0)

这与接受的答案基本相同,但不太重视回调。 GUI是回调方法还是其他什么都没关系。问题是如何将对象传递给请求处理程序。解决方案确实是一个请求处理程序工厂,它接收GUI(对象)并在创建它时将其传递给处理程序。有人会建议通过服务器传递对象(GUI),但它很尴尬,因为服务器与它无关。它甚至没有看到它。工厂也更灵活 - 你甚至可以根据要求制作处理程序!

工厂必须在处理程序的构造函数中传递对象(GUI),因此需要扩展此构造函数(我假设Python 3 - 使用super()):

SELECT cast_and_crew ->> 'content_id' AS content_id 
  FROM content_table 
 WHERE cast_and_crew ->> 'Actor' -> 'personName' = 'C. R. Simha'

BTW,目前,没有必要像https://bugs.python.org/issue29947中讨论的那样继承class SingleTCPHandler(SocketServer.BaseRequestHandler): """ One instance per connection. """ def __init__(self, request, client_address, server, GUI): # The GUI must be passed before we call the parent constructor # because it actually handles the request and finishes it. self._GUI = GUI super().__init__(request, client_address, server) def handle(self): data = Net.recv_from_socket(self.request) self._GUI.run(str("RECV'd message: %s" % data)) 。我这样做,因为他们在文档中提出了建议,但可以使用任何处理程序 - 无需提供SocketServer.BaseRequestHandlersetuphandle API。除了必须处理请求之外,处理程序没有约束。我们只需要定义工厂方法,当服务器调用时,它将实例化处理程序(并启动它),同时将GUI对象和连接(finish)传递给客户端:

request

以这种方式使用:

class RequestHandlerFactory:
    def __init__(self, GUI):
        self._GUI = GUI    

    def start(self, request, client_address, server):
        # The factory could even pass a different handler at each request!
        # The application could change the handler while the server is running!
        return SingleTCPHandler(self, request, client_address, server, self._GUI)

答案 2 :(得分:0)

这对我有用:

class MyServer():
    def __init__(self, myGui, host='', port=8875):
        myServer = socketserver.TCPServer((host, port), functools.partial(MyHandler, myGui))
        myServer.serve_forever()

class MyHandler(socketserver.BaseRequestHandler): 
    def __init__(self, myGui, socket, client_address, tcpServer):
        self.myGui = myGui
        super().__init__(socket, client_address, tcpServer) 

    def handle(self):
        ...