zoukankan      html  css  js  c++  java
  • tornado websocket

    一、长轮询

    在扫码登录的页面,服务器是如何知道用户有没有在手机上扫码登录?

    通过长轮询的方式,每隔几秒向服务器发送一个请求,服务器判断这个请求中有没有用户扫码。

    缺点

    1.开销大

    2.浪费资源

    3.消耗流量

    二、websocket概念

    长轮询消耗太多资源,其中主要原因是客户端和服务端并没有一直连接在一起。

    websocket起到的作用,就是让客户端和服务器一直连接在一起。

    (一).websocket官话描述

    WebSocket协议是基于TCP的一种新的HTML5网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并被RFC7936所补充规范。

    (二).简单理解

    客户端和服务器一直连接在一起

    三、websocket服务端编程

    (一).导包

    import tornado.websocket

    (二).编写一个基类

    class BaseWebSocketHandler(tornado.websocket.WebSocketHandler, SessionMixin):
        def get_current_user(self):
            current_user = self.session.get('user')
                if current_user:
                    return current_user
                return None
    View Code

    (三).跳转的Handler

    class IndexHandler(BaseHandler):
        @authenticated
        def get(self):
            self.render('08websocket.html')
    View Code

    (四).websocket的Handler

    class MessageWSHandler(BaseWebSocketHandler):
        users = set()
    
        def open(self):
            MessageWSHandler.users.add(self)
    
        def on_message(self, message):
            for u in self.users:
                u.write_message(
                    '%s-%s-说:%s' % (
                        self.current_user,
                        datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                        message
                    ))
    
        def on_close(self):
            if self in MessageWSHandler.users:
                MessageWSHandler.users.remove(self)
    View Code

    (五).为WebsocketHandler添加路由

    (六).总结

    Tornado 定义了 tornado.websocket.WebSocketHandler 这个类,用于处理 WebSocket 链接的请求。

    必须继承该类并重写 open()、on_message()、on_close() 这三个函数,Tornado会自动去调用这三个函数。

    (1).WebSocketHandler还提供了两个可以主动操作的WebSocket函数

    WebSocketHandler.write_message(message)函数:用于向与本链接相对应的客户端写消息。

    WebSocketHandler.close(code=None,reason=None)函数:主动关闭 WebSocket链接。其中的code和reason用于告诉客户端链接被关闭的原因。参数code必须是一个数值,而reason是一个字符串。

    四、webscoket客户端编程

    WebSocket是HTML5的标准之一,主流浏览器的web客户端编程语言Javascript已经支持WebSocket的客户端编程。

    (一).初始化WebSocket对象

    var socket = new WebSocket(url);

    (二).处理函数

    WebSocket.onopen:此事件发生在 WebSocket 链接建立时

    WebSocket.onmessage:此事件发生在收到了来自服务器的消息时

    WebSocket.onclose:此事件发生在与服务器的链接关闭时

    WebSocket.onerror:此事件发生在通信过程中有任何错误时

    (三).主动操作函数

    WebSocket.send(data):向服务器发送消息

    WebSocket.close():主动关闭现有链接

    五、完整代码

    (一).编写Handler

    class BaseHandler(tornado.web.RequestHandler):
        def get_current_user(self):
            current_user = self.get_secure_cookie('ID')
            if current_user:
                return current_user
            return None
    
    
    class BaseWebsocketHandler(tornado.websocket.WebSocketHandler):
        def get_current_user(self):
            current_user = self.get_secure_cookie("ID")
            if current_user:
                return current_user
            return None
    
    
    class MessageWSHandler(BaseWebsocketHandler):
        users = set()
    
        def show_message(self, message):
            for u in self.users:
                u.write_message(message)
    
        def on_open(self):
            print("coming open...")
            self.show_message("{}进入!".format(""))
            MessageWSHandler.users.add(self)  # self是user的实例
    
        def on_message(self, message):
            print(message)
            for u in self.users:
                self.show_message("{}说:{}".format("", message))
            # self.write_message(message)
    
        def on_close(self):
            if self in MessageWSHandler.users:
                self.show_message("{}退出!".format(""))
                MessageWSHandler.users.remove(self)
    
    
    class MainHandler(BaseWebsocketHandler):
        @authenticated
        def get(self):
            self.render("08websocket.html")
    View Code

    (二).编写模板文件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title> WebSocket </title>
        <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
        <style>
            * {
                margin: 0;
                padding: 0;
            }
    
            .box {
                width: 800px;
                margin-left: auto;
                margin-right: auto;
                margin-top: 25px;
            }
    
            #text {
                width: 685px;
                height: 130px;
                border: 1px solid skyblue;
                border-radius: 10px;
                font-size: 20px;
                text-indent: 1em;
                resize: none;
                outline: none;
            }
    
            #text::placeholder {
                color: skyblue;
            }
    
            .btn {
                width: 100px;
                margin: -27px 0 0px 8px;
            }
    
            #messages {
                padding-left: 10px;
                font-size: 25px;
            }
    
            #messages li {
                list-style: none;
                color: #000;
                line-height: 30px;
                font-size: 18px;
    
            }
        </style>
    </head>
    <body>
    <div class="box">
        <div>
            <textarea id="text" placeholder="请输入您的内容"></textarea>
            <a href="javascript:WebSocketSend();" class="btn btn-primary">发送</a>
        </div>
        <ul id="messages">
        </ul>
    </div>
    
    
    <script src="{{ static_url('js/jquery-2.2.0.min.js') }}"></script>
    
    
    <script type="text/javascript">
    
        var mes = document.getElementById('messages');
        if ("WebSocket" in window) {
            mes.innerHTML = "发送WebSocket请求成功!";
            // var ws = new WebSocket("ws://127.0.0.1:8000/websocket");
            var ws = new WebSocket("ws://47.98.139.237:8888/websocket");
            ws.onopen = function () {
                alert('连接已打开请聊天')
            };
            ws.onmessage = function (goudan) {
    
                var received_msg = goudan.data;
    
                var aLi = $("<li>" + received_msg + "</li>");
                // $(mes).append($(aLi)) //  方法一
                // $(aLi).appendTo(mes); //  方法二
                $(mes).prepend($(aLi))
            };
            ws.onclose = function () {
                mes.innerHTML = mes.innerHTML + "<br>连接已经关闭...";
            };
        } else {
            mes.innerHTML = "发送WebSocket请求失败!"
        }
    
        function WebSocketSend() {
            ws.send($("#text").val());
            $("#text").val("")
        }
    </script>
    
    </body>
    </html>
    View Code

    前端脚本是jquery写法,必须引入jquery.js

    六、可能会踩到的坑

    (一).代理插件引起的websocket失败

    (1).问题描述

    我在Chrome上安装了一个代理插件,进行科学上网。但使用websocket的时候,会报错。把报错的英文进行翻译:通过代理服务器建立隧道失败。

    没有代理插件的浏览器就可以成功发送消息,而且在Chrome上也可以接收到已发送过的数据,但是发送数据就会失败。

    (2).原因

    代理是把请求通过代理服务器转发给真正的服务器。一般代理只做了http和https,基本不会去做websocket,哪怕是专业的代理。

    (3).解决办法

    1.退出代理账号,然后重新访问,一切都正常了。

    2.换个没有代理插件的浏览器。

    3.加白名单,不让插件去代理websocket

    (4).补充

    尚不清楚蓝灯或者其他科学上网方式会不会遇到类似问题。如果有类似问题,一定要直接评论哈~让别人不要踩坑了

  • 相关阅读:
    搜查令——中期总结
    搜查令——第二周
    软件工程团队项目——搜查令
    初入博客园
    初步了解Ajax
    APPLET基础
    LoggingFilter Session 以及Async
    Session
    XML定义 用途 工作原理及未来
    Linux安装Axis C构建WebService服务
  • 原文地址:https://www.cnblogs.com/quanquan616/p/9614172.html
Copyright © 2011-2022 走看看