zoukankan      html  css  js  c++  java
  • Tornado长轮询和WebSocket

    Http协议是一种请求响应式协议, 不允许服务端主动向客户端发送信息.

    短轮询是一种简单的实现服务端推送消息的解决方案, 客户端以一定间隔自动向服务端发送刷新请求, 服务端返回要推送的消息作为响应.

    短轮询存在严重缺陷:

    • 短轮询需要进行高频率的网络通信, 且收到大多数轮询请求时服务端没有消息需要推送.

    • 需要维护大量Http连接, 严重消耗资源

    如果手写一个短轮询的话你会发现, 短轮询带来的问题不止这些.

    长轮询

    长轮询是客户端向服务端发送一个刷新请求, 并保持连接打开. 服务端收到请求后不立即响应,等到需要推送消息时再返回. 然后, 客户端再次发送刷新请求并等待推送.

    长轮询不再需要频繁发送刷新请求, 但是长期等待的Http连接可能断开, 需要考虑异常处理.

    长轮询请求等待过程中服务端处理进程不能被阻塞, tornado的异步IO机制可以方便的使用长轮询.

    import tornado.httpserver
    from tornado.ioloop import IOLoop
    import tornado.options
    import json
    from tornado.web import Application, RequestHandler, asynchronous
    
    
    class ChatApp(Application):
        def __init__(self):
            handlers = [
                (r'/new-message', NewMsgHandler),
                (r'/update-message', UpdateMsgHandler)
            ]
            super(ChatApp, self).__init__(self, handlers=handlers)
            self.cache = []
    
    
    class NewMsgHandler(RequestHandler):
        def __init__(self, app):
            self.app = app
    
        def post(self):
            msg = self.get_argument('msg')
            self.app.cache.append(msg)
    
    
    class UpdateMsgHandler(RequestHandler):
        def __init__(self, app):
            self.app = app
    
        @asynchronous
        def post(self):
            if self.request.connection.stream.closed():
                return
            response_json = json.dumps(self.app.cache)
            self.write(response_json)
            self.finish()
    
    
    def main():
        tornado.options.parse_command_line()
        app = ChatApp()
        http_server = tornado.httpserver.HTTPServer(app)
        http_server.listen(options.port)
        tornado.ioloop.IOLoop.instance().start()
    
    if __name__ == '__main__':
        main()
    

    示例的完整代码,请去草民的仓库

    这篇博客提供了一个更为强大的基于长轮询的聊天室, 而且草民非常喜欢他的代码风格.

    tornado的长轮询聊天室例子分析

    长连接断开的处理机制可以参考这篇文章

    WebSocket

    WebSocket是HTML5协议中提出的客户-服务器通信协议, 它允许双方以类似TcpSocket的方式进行通信.

    它基于标准Http协议实现, 但使用新的ws://URL格式.

    Tornado在websocket模块中提供了一个WebSocketHandler类,

    • open方法在一个新的WebSocket连接打开时被调用,

    • on_message方法在连接接收到新的消息时被调用

    • on_close方法在客户端关闭时被调用

    • write_message(message, binary=False)方法可以通过WebSocket向对方发送数据

        - 若binary=False, message可以是string或者dict(会被自动编码为JSON), 
      
        - 若binary=True, message可以是任意byte string
      

    继承WebSocketHandler并重写自己上述方法,实现基于WebSocket的应用.

    来自tornado官方文档的示例:

    class EchoHandler(WebSocketHandler):
    
    	def allow_draft76(self):
        	return True
    
    	def check_origin(self, origin):
        	return True
    
        def open(self):
            print "new client opened"
    
        def on_close(self):
            print "client closed"
    
        def on_message(self, message):
            self.write_message(message)
    

    allow_draft76check_origin用于进行安全性校验, 只有它们都返回True时WebSocket才能正常连接.

    tornado WebSocketHandler文档

    Python WebSocket

    WebSocket虽然是为Web应用设计的, 为了减轻后端的开发压力可以采用WenSocket代替Tcp Socket与后端交互.

    Websocket-client是Python Websocket支持包,可以使用pip安装:

    pip install websocket-client

    PyPi websocket-client

    websocket-client提供了几个低级API:

    • 建立websocket连接

    ws = create_connection("ws://echo.websocket.org/")

    • 发送消息

    ws.send(msg)

    • 接收消息

    result = ws.recv()

    • 关闭连接

    ws.close()

    websocket也提供了JS风格的API, 来自官方文档的示例:

    import websocket
    import thread
    import time
    
    def on_message(ws, message):
        print message
    
    def on_error(ws, error):
        print error
    
    def on_close(ws):
        print "### closed ###"
    
    def on_open(ws):
        def run(*args):
            for i in range(3):
                time.sleep(1)
                ws.send("Hello %d" % i)
            time.sleep(1)
            ws.close()
            print "thread terminating..."
        thread.start_new_thread(run, ())
    
    
    if __name__ == "__main__":
        websocket.enableTrace(True)
        ws = websocket.WebSocketApp(
            "ws://echo.websocket.org/",
            on_message = on_message,
            on_error = on_error,
            on_close = on_close
        )
        ws.on_open = on_open
        ws.run_forever()
    

    更多信息请参见Github websocket-client

  • 相关阅读:
    JavaScript原生对象属性和方法详解——Array对象[转]
    SVN的trunk branch tag (二)
    git入门使用摘录
    文字画工具推荐
    mysql 基础操作
    mobile 测试入门思维导图
    淘宝性能测试线下测试与线上跟踪体系
    github使用入门 之GIT GUI Windows版
    C++ 单向链表反转
    shell脚本实例一,移动文件夹中大于2000B的文件到另一个文件夹
  • 原文地址:https://www.cnblogs.com/Finley/p/5517769.html
Copyright © 2011-2022 走看看