• Tornado websocket应用


    应用场景

    WebSocket 的特点如下

    • 适合服务器主动推送的场景(好友上线,即时聊天信息,火灾警告,股票涨停等)
    • 相对于Ajax和Long poll等轮询技术,它更高效,不耗费网络带宽和计算资源
    • 它仍然与HTTP完成网络通信
    • 不受企业防火墙拦截

    通信原理

     1.WebSocket 客户端连接报文
    GET /webfin/websocket/ HTTP/1.1
    Host: localhost
    Upgrade: websocket  # 建立webSocket链接
    Connection: Upgrade  # 建立链接
    Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==   # 密钥
    Origin: <a href="http://localhost/"><code>http://localhost</code></a>:8080
    Sec-WebSocket-Version: 13  # 版本是13

    客户端发起的 WebSocket 连接报文类似传统 HTTP 报文,”Upgrade:websocket”参数值表明这是 WebSocket 类型请求,“Sec-WebSocket-Key”是 WebSocket 客户端发送的一个 base64 编码的密文,要求服务端必须返回一个对应加密的“Sec-WebSocket-Accept”应答,否则客户端会抛出“Error during WebSocket handshake”错误,并关闭连接。

    2、服务端收到报文后返回的数据格式类似:

    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=

    “Sec-WebSocket-Accept”的值是服务端采用与客户端一致的密钥计算出来后返回客户端的,“HTTP/1.1 101 Switching Protocols”表示服务端接受 WebSocket 协议的客户端连接,经过这样的请求-响应处理后,客户端服务端的 WebSocket 连接握手成功, 后续就可以进行 TCP 通讯了

    服务端编程:

    tornadowebsocokt入口函数,需要继承tornado.websocket.WebSocketHandler,并显现open(),on_message(),on_close()函数

    还提供了开发者主动操作的websocket函数

    WebSocketHandler.write_meassage(message,binary=False) 用于向本链接对应的客户端写消息

    WebSocketHandler.close(code=None,reason=None)函数:主动关闭链接,并告知客户端关闭的原因,code参数必须是一个数值,reason必须是一个字符串

    实例

    import tornado.web
    import tornado.ioloop
    import tornado.websocket
    
    from tornado.options import define,options,parse_command_line
    
    define('port',default=8888,help='run the given port',type=int)
    
    clients = dict() # 客户端session字典
    
    class IndexHandler(tornado.web.RequestHandler):
        @tornado.web.asynchronous
        def get(self):
            self.render('index.html')
    
    class MyWebSocketHandler(tornado.websocket.WebSocketHandler):
        def open(self, *args):  # 有新连接时被调用
            self.id = self.get_argument('Id')
            self.stream.set_nodelay(True)
            clients[self.id]={"id":self.id,"object":self} # 保存session到clients字典中
    
        def on_message(self, message): # 收到消息时被调用
            print("client %s received a message : %s" % (self.id,message))
    
        def on_close(self):   # 关闭链接时被调用
            if self.id in clients:
                del clients[self.id]
                print("client %s is closed" % (self.id))
    
        def check_origin(self, origin):
            return True
    
    
    app = tornado.web.Application([(r'/', IndexHandler), (r'/websocket', MyWebSocketHandler), ])
    
    import threading
    import time
    
    # 启动单独的线程运行此函数,每隔1秒向所有客户端推送当前时间
    def sendTime():
        import datetime
        while True:
            for key in clients.keys():
                msg = str(datetime.datetime.now())
                clients[key]['object'].write_message(msg) # 通过WebSocketHandler.write_meassage函数推送时间消息
                print("write to client %s : %s" % (key,msg))
            time.sleep(1)
    
    if __name__ == '__main__':
        threading.Thread(target=sendTime).start() # 启动推送时间线程
        parse_command_line()
        app.listen(options.port)
        tornado.ioloop.IOLoop.instance().start() # 挂起运行

    客户端编程

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <a href="javascript:WebSocketTest()">run websocket</a>
    <div id="messages" style="height: 200px;background: black;color: #e0e0e0;"></div>
    
    <script type="text/javascript">
        var messageContainer = document.getElementById('messages');
        function WebSocketTest() {
            if ("WebSocket" in window){
                messageContainer.innerHTML = '你的浏览器支持websocket';
                var ws = new WebSocket('ws://localhost:8888/websocket?Id=12345');
                ws.onopen = function () {
                    ws.send("message to send");
                };
                ws.onmessage = function (evt) {
                    var received_msg = evt.data;
                    messageContainer.innerHTML = messageContainer.innerHTML+"<br/>message is received:"+received_msg;
                };
                ws.onclose = function () {
                    messageContainer.innerHTML = messageContainer.innerHTML+"<br/>链接已经关闭";
                };
    
            } else {
                 messageContainer.innerHTML = '你的浏览器不支持websocket';
            }
        }
    </script>
    </body>
    </html>

  • 相关阅读:
    Spring框架之什么是IOC的功能?
    Spring框架的特点
    spring框架的概述与入门
    struts框架总结
    struts框架之总结OGNL表达式的特殊的符号
    struts框架值栈问题七之EL表达式也会获取到值栈中的数据
    struts框架问题六之从值栈中获取值
    struts框架问题五之向值栈中保存数据
    struts框架问题四之获取到值栈的对象
    java获取屏幕密度
  • 原文地址:https://www.cnblogs.com/Erick-L/p/7079039.html
Copyright © 2020-2023  润新知