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).補充

尚不清楚藍燈或者其他科學上網方式會不會遇到類似問題。如果有類似問題,一定要直接評論哈~讓別人不要踩坑了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM