Tornado-如何在另一个函数中调用处理程序

Posted

技术标签:

【中文标题】Tornado-如何在另一个函数中调用处理程序【英文标题】:Tornado- how to call a handler in another function 【发布时间】:2016-07-29 18:50:29 【问题描述】:

我目前正在尝试使用 Tornado 的 web-socket 处理程序在每次调用某个函数时更新仪表板。这是处理程序:

class WebSocketHandler(websocket.WebSocketHandler):
    clients = []
    def open(self):
        logging.info("WEBSOCKET OPEN")
        WebSocketHandler.clients.append(self)
    def on_message(self, message):
        logging.info("message from websocket recieved")
        self.write_message("WebSocket connected")
    def on_close(self):
        logging.info("WEBSOCKET closed")

这里是加载时连接 WebSocket 的客户端脚本:

  function WebSocketTest()
 var ws = 0;
   ws = new WebSocket("ws://localhost:8008/WEB");
   ws.onopen = function()
    
    ws.send("initial connect")
    

  ws.onmessage = function (evt)
  
    console.log(evt.data)
  ;

  ws.onclose = function()
  
    console.log("closed ");
  ;

websockets 连接成功。

我需要从WebSocketHandler 调用write_message,但我很困惑它的实例是什么?我一直遇到的错误是 self isn't defined 但我不确定 self 到底是什么?我知道,每当客户端尝试加载 ^/WEB$ 时,WebSocketHandler 就会运行

编辑:这是我的server.py 文件,我需要在spawn callback 调用itercheckers 之后立即调用write_message

class Server():



@classmethod
def run(cls):
    options.parse_command_line()
    # Start web
    template_path = os.path.join(os.path.dirname(__file__), 'templates')
    jinja2loader = Jinja2Loader(template_path)
    kwargs = dict(
        template_loader=jinja2loader,
        static_path=os.path.join(os.path.dirname(__file__), 'static'),
        debug=True,
        login_url="/auth/login",
        cookie_secret="dn470h8yedWF9j61BJH2aY701i6UUexx"
    )
    app = web.Application(handlers, **kwargs).listen(
        configuration['server']['port'],)

    # Reset events
    @gen.coroutine
    def reset(parent=None):
        if parent is None:
            parent = configuration
        # Reset event happyness
        yield events.reset_happy(parent)
        # Read last status
        data = yield events.get(parent)
        # Read and set happy from the last status
        happy = (data or ).get('status', events.STATUS_OK) \
            in events.HAPPY
        yield events.set_happy(parent, happy)
        # Iterate sub-events
        for event in parent['events']:
            yield reset(event)

    ioloop.IOLoop.current().run_sync(reset)



    # Start checkers
    def itercheckers(parent):
        index = 0
        for event in parent.get('events', []):
            if 'checker' in event:
                checker = event['checker']
                p, m = checker['class'].rsplit('.', 1)
                ioloop.IOLoop.current().spawn_callback(
                    getattr(importlib.import_module(p), m)(
                        event=event,
                        frequency=checker.get('frequency', 1),
                        params=checker['params']
                    ).run)
            index += 1
            itercheckers(event)
    itercheckers(configuration)



    # Start alerts
    ioloop.IOLoop.current().run_sync(alerts.reset)
    for alert in configuration['alerts']:
        p, m = alert['class'].rsplit('.', 1)
        ioloop.IOLoop.current().spawn_callback(
            getattr(importlib.import_module(p), m)(
                alert=alert
            ).run
        )

    # Start loop
    ioloop.IOLoop.current().start()

【问题讨论】:

您如何访问它?你不去 ws://localhost:8000/ws 吗?您必须使用 js 制作 html 页面并在该页面上打开控制台以查看输出是什么 不,我愿意。访问 WebSocketHandler 的链接是“/WEB”。 new WebSocket("ws://localhost:8008/WEB"); 连接我 【参考方案1】:

首先,self 关键字指向当前正在处理的 websocket 客户端。要使用 tornado websockets,您必须初始化 tornado 应用程序

app = web.Application([
    (r'/ws', WSHandler), #tells it to redirect ws:// to websocket handler
#Choose different names from defaults because of clarity
])

if __name__ == '__main__':
    app.listen(5000) #listen on what port
    ioloop.IOLoop.instance().start()

那么你必须有 WSHandler 类你将 websockets 流量指向

class WSHandler(websocket.WebSocketHandler):
    #crossdomain connections allowed
    def check_origin(self, origin):
        return True
    #when websocket connection is opened
    def open(self):
       print("Client connected ")

    def on_close(self):
       print("Client disconnected")

    def on_message(self,message):
       self.write_message(message) #echo back whatever client sent you

所以完整的应用看起来像

from tornado import websocket, web, ioloop
clients = [] 

#whenever you want to broadcast to all connected call this function
def broadcast_message(msg):
    global clients 
    for client in clients:
        client.write_message(msg)

class WSHandler(websocket.WebSocketHandler):
    #crossdomain connections allowed
    def check_origin(self, origin):
        return True
    #when websocket connection is opened
    def open(self):
       #here you can add clients to your client list if you want
       clients.append(self)
       print("Client connected ")

    def on_close(self):
       clients.remove(self)
       print("Client disconnected")

    def on_message(self,message):
       self.write_message(message) #echo back whatever client sent you

app = web.Application([
    (r'/ws', WSHandler), #tells it to redirect ws:// to websocket handler
#Choose different names from defaults because of clarity
])

if __name__ == '__main__':
    app.listen(5000) #listen on what port
    ioloop.IOLoop.instance().start()

现在用 js 连接到它

function WebSocketTest()
 
   var ws = new WebSocket("ws://localhost:5000/ws");
    ws.onopen = function()
    
       ws.send("initial connect")
    

    ws.onmessage = function (evt)
    
       console.log(evt.data) 
    ;

    ws.onclose = function()
    
       console.log("closed ");
    ;

我还没有测试过,但应该可以工作

【讨论】:

对不起,我应该包含它,但我有一个 server.py 文件,我在其中创建 web.Application 并传递处理程序列表。我绝对可以将我的客户连接到服务器。我想弄清楚的是如何根据服务器端事件将数据从服务器发送到客户端。 您要发送给特定客户或所有客户 所有客户。这是一个状态仪表板,每当调用特定函数时我都需要更新它 好的,我马上编辑服务器代码......现在你只需调用广播消息,带有消息参数broadcast_message("ABC"),它会将该消息发送到所有连接的客户端,但你可以调用它只有在它声明之后,因为 python 被解释它不能看到前面

以上是关于Tornado-如何在另一个函数中调用处理程序的主要内容,如果未能解决你的问题,请参考以下文章

如何查看在另一个程序中调用的函数[关闭]

如何从 C++ 代码引发事件并在另一个进程的 C# 代码中调用处理程序?

如何在另一个 defn 中调用一个 defn 函数以及如何在 Clojure 中调试

如何在tornado中以异步的方式调用同步函数

在另一个单独的异步调用解决之前,如何防止/锁定函数返回?

ExtJS:如何在另一个函数中调用一个函数?