【问题标题】:How to run functions outside websocket loop in python (tornado)如何在python(龙卷风)中的websocket循环之外运行函数
【发布时间】:2012-09-10 20:06:23
【问题描述】:

我正在尝试通过 websockets 设置一个公共 Twitter 流的小示例。这是我的 websocket.py,它正在工作。

我想知道的是:如何从类 WSHandler 的“外部”与 websocket 交互(即,不仅在接收来自 websocket.js 的消息时回答)?假设我想在同一个脚本中运行一些其他功能,这些功能会发布“你好!”每五秒钟将其发送到 websocket(浏览器),而无需来自客户端的任何交互。我怎么能这样做?

所以我想这是一个基本的初学者问题,关于如何处理下面的类。任何方向的任何指示都将不胜感激!

import os.path
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web

# websocket
class FaviconHandler(tornado.web.RequestHandler):
    def get(self):
        self.redirect('/static/favicon.ico')

class WebHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("websockets.html")

class WSHandler(tornado.websocket.WebSocketHandler):
    def open(self):
        print 'new connection'
        self.write_message("Hi, client: connection is made ...")

    def on_message(self, message):
        print 'message received: \"%s\"' % message
        self.write_message("Echo: \"" + message + "\"")
        if (message == "green"):
            self.write_message("green!")

    def on_close(self):
        print 'connection closed'



handlers = [
    (r"/favicon.ico", FaviconHandler),
    (r'/static/(.*)', tornado.web.StaticFileHandler, {'path': 'static'}),
    (r'/', WebHandler),
    (r'/ws', WSHandler),
]

settings = dict(
    template_path=os.path.join(os.path.dirname(__file__), "static"),
)

application = tornado.web.Application(handlers, **settings)

if __name__ == "__main__":
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

【问题讨论】:

    标签: python websocket tornado


    【解决方案1】:

    你可以打电话

    IOLoop.add_timeout(deadline, callback)
    

    在指定的截止时间超时调用回调(一次,但您可以重新安排),或使用

    tornado.ioloop.PeriodicCallback 如果您有更周期性的任务。

    见:http://www.tornadoweb.org/en/stable/ioloop.html#tornado.ioloop.IOLoop.add_timeout

    更新:一些例子

    import datetime
    
    def test():
        print "scheduled event fired"
    ...
    
    if __name__ == "__main__":
        http_server = tornado.httpserver.HTTPServer(application)
        http_server.listen(8888)
        main_loop = tornado.ioloop.IOLoop.instance()
        # Schedule event (5 seconds from now)
        main_loop.add_timeout(datetime.timedelta(seconds=5), test)
        # Start main loop
        main_loop.start()
    

    它会在 5 秒后调用 test()

    更新 2:

    import os.path
    import tornado.httpserver
    import tornado.websocket
    import tornado.ioloop
    import tornado.web
    
    # websocket
    class FaviconHandler(tornado.web.RequestHandler):
        def get(self):
            self.redirect('/static/favicon.ico')
    
    class WebHandler(tornado.web.RequestHandler):
        def get(self):
            self.render("websockets.html")
    
    class WSHandler(tornado.websocket.WebSocketHandler):
        def open(self):
            print 'new connection'
            self.write_message("Hi, client: connection is made ...")
            tornado.ioloop.IOLoop.instance().add_timeout(datetime.timedelta(seconds=5), self.test)
    
        def on_message(self, message):
            print 'message received: \"%s\"' % message
            self.write_message("Echo: \"" + message + "\"")
            if (message == "green"):
                self.write_message("green!")
    
        def on_close(self):
            print 'connection closed'
    
        def test(self):
            self.write_message("scheduled!")
    
    handlers = [
        (r"/favicon.ico", FaviconHandler),
        (r'/static/(.*)', tornado.web.StaticFileHandler, {'path': 'static'}),
        (r'/', WebHandler),
        (r'/ws', WSHandler),
    ]
    
    settings = dict(
        template_path=os.path.join(os.path.dirname(__file__), "static"),
    )
    
    application = tornado.web.Application(handlers, **settings)
    
    import datetime
    
    if __name__ == "__main__":
        http_server = tornado.httpserver.HTTPServer(application)
        http_server.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    

    【讨论】:

    • 谢谢。但具体在哪里?我试过调用 WSHandler,但得到“必须用 WSHandler 实例调用......”
    • 我使用 add_timeout() 添加了一些示例。
    • 你不会碰巧知道如何从test() 调用WSHandler 吗?这样我就可以从那里打电话给self.write_message()
    • IOLoop.instance() 是一个单例(在典型使用中)。你可以多次调用 instance() 并返回相同的单例。
    • 查看第二次更新。它在连接 5 秒后发送预定消息。
    【解决方案2】:

    我偶然发现了类似的问题。这是我的解决方案。希望这对那里的人有帮助

    wss = []
    class wsHandler(tornado.websocket.WebSocketHandler):
        def open(self):
            print 'Online'
            if self not in wss:
                wss.append(self)
    
        def on_close(self):
            print 'Offline'
            if self in wss:
                wss.remove(self)
    
    def wsSend(message):
        for ws in wss:
            ws.write_message(message)
    

    要向您的 websocket 发送消息,只需使用以下命令:

    wsSend(message)
    

    wsSend 更新

    我偶尔会遇到 wsSend 异常。为了修复它,我将代码修改为以下内容:

    def wsSend(message):
        for ws in wss:
            if not ws.ws_connection.stream.socket:
                print "Web socket does not exist anymore!!!"
                wss.remove(ws)
            else:
                ws.write_message(message)
    

    【讨论】:

    • Tornado 的新手,所以.....您介意在这个非常有希望的答案中添加必要的样板吗,因为我想看看它如何工作(如果我理解正确的话)更多比一个 websocket 处理程序。那你能举一个 if __name__ == "__main__" 块的例子,它会初始化 IOLoop(s?) 和 handler(s?)。乍一看似乎很优雅。
    • Thomas,我很乐意为您提供帮助,但我也不是 Tornado 专家已经有一段时间了。但据我所知,Tornado 有很好的文档,你可以随时浏览源代码。祝你好运!
    【解决方案3】:

    一种方法是使用 pub-sub 模块。

    意味着您有您的连接订阅,而不是为每个连接设置超时,您只需在所述时间段后为发布设置一个超时。

    实施最多的可能之一是 redis。还有一些专门针对龙卷风的模块:例如toredisbrükva

    当然,对于一个简单的页面来说,这可能不是必需的,但可以很好地扩展,并且一旦你设置它就可以很好地维护/扩展。

    【讨论】:

      猜你喜欢
      • 2023-03-30
      • 2017-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多