zoukankan      html  css  js  c++  java
  • 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>

  • 相关阅读:
    缓冲字符流 java.io.BufferedWriter ,java.io.BufferedReader,缓冲字符输出流:PrintWriter
    转换流读写操作 java.io.OutputStreamWriter ,java.io.InputStreamReader
    对象流,它们是一对高级流,负责即将java对象与字节之间在读写的过程中进行转换。 * java.io.ObjectOutputStream * java.io.ObjectInputStream
    flush() 缓冲输出流的缓冲区问题
    使用文件流与使用缓冲流完成文件的复制操作性能对比,文件流 FileInputStream FileOutputStream 缓冲流: BufferedInputStream BufferedOutputStream
    RandomAccessFile()实现用户注册功能, 新增,查询,更新
    RandomAccessFile实现简易记事本工具操作
    对比两种方式复制文件的效率
    File 删除给定的文件或目录
    RandomAccessFile(),读写文件数据的API,以及复制文件操作
  • 原文地址:https://www.cnblogs.com/Erick-L/p/7079039.html
Copyright © 2011-2022 走看看