(2018-05-30.Python從Zero到One)8、(Tornado)異步與WebSockets__1.7.3 WebSocket

7.3 WebSocket

WebSocket是HTML5規(guī)范中新提出的客戶端-服務(wù)器通訊協(xié)議,協(xié)議本身使用新的ws://URL格式。

WebSocket 是獨立的、創(chuàng)建在 TCP 上的協(xié)議,和 HTTP 的唯一關(guān)聯(lián)是使用 HTTP 協(xié)議的101狀態(tài)碼進行協(xié)議切換,使用的 TCP 端口是80,可以用于繞過大多數(shù)防火墻的限制。

WebSocket 使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端直接向客戶端推送數(shù)據(jù)而不需要客戶端進行請求,兩者之間可以創(chuàng)建持久性的連接,并允許數(shù)據(jù)進行雙向傳送。

目前常見的瀏覽器如 Chrome、IE、Firefox、Safari、Opera 等都支持 WebSocket,同時需要服務(wù)端程序支持 WebSocket。

1. Tornado的WebSocket模塊

Tornado提供支持WebSocket的模塊是tornado.websocket,其中提供了一個WebSocketHandler類用來處理通訊。

WebSocketHandler.open()

當一個WebSocket連接建立后被調(diào)用。

WebSocketHandler.on_message(message)

當客戶端發(fā)送消息message過來時被調(diào)用,注意此方法必須被重寫。

WebSocketHandler.on_close()

當WebSocket連接關(guān)閉后被調(diào)用。

WebSocketHandler.write_message(message, binary=False)

向客戶端發(fā)送消息messagea,message可以是字符串或字典(字典會被轉(zhuǎn)為json字符串)。若binary為False,則message以utf8編碼發(fā)送;二進制模式(binary=True)時,可發(fā)送任何字節(jié)碼。

WebSocketHandler.close()

關(guān)閉WebSocket連接。

WebSocketHandler.check_origin(origin)

判斷源origin,對于符合條件(返回判斷結(jié)果為True)的請求源origin允許其連接,否則返回403??梢灾貙懘朔椒▉斫鉀QWebSocket的跨域請求(如始終return True)。

2. 前端JavaScript編寫

在前端JS中使用WebSocket與服務(wù)器通訊的常用方法如下:

var ws = new WebSocket("ws://127.0.0.1:8888/websocket"); // 新建一個ws連接
ws.onopen = function() {  // 連接建立好后的回調(diào)
   ws.send("Hello, world");  // 向建立的連接發(fā)送消息
};
ws.onmessage = function (evt) {  // 收到服務(wù)器發(fā)送的消息后執(zhí)行的回調(diào)
   alert(evt.data);  // 接收的消息內(nèi)容在事件參數(shù)evt的data屬性中
};

3. 在線聊天室的小Demo

后端代碼 server.py
# coding:utf-8

import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options
import os
import datetime

from tornado.web import RequestHandler
from tornado.options import define, options
from tornado.websocket import WebSocketHandler

define("port", default=8000, type=int)

class IndexHandler(RequestHandler):
    def get(self):
        self.render("index.html")

class ChatHandler(WebSocketHandler):

    users = set()  # 用來存放在線用戶的容器

    def open(self):
        self.users.add(self)  # 建立連接后添加用戶到容器中
        for u in self.users:  # 向已在線用戶發(fā)送消息
            u.write_message(u"[%s]-[%s]-進入聊天室" % (self.request.remote_ip, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))

    def on_message(self, message):
        for u in self.users:  # 向在線用戶廣播消息
            u.write_message(u"[%s]-[%s]-說:%s" % (self.request.remote_ip, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), message))

    def on_close(self):
        self.users.remove(self) # 用戶關(guān)閉連接后從容器中移除用戶
        for u in self.users:
            u.write_message(u"[%s]-[%s]-離開聊天室" % (self.request.remote_ip, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))

    def check_origin(self, origin):
        return True  # 允許WebSocket的跨域請求

if __name__ == '__main__':
    tornado.options.parse_command_line()
    app = tornado.web.Application([
            (r"/", IndexHandler),
            (r"/chat", ChatHandler),
        ],
        static_path = os.path.join(os.path.dirname(__file__), "static"),
        template_path = os.path.join(os.path.dirname(__file__), "template"),
        debug = True
        )
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.current().start()

前端代碼index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>聊天室</title>
</head>
<body>
    <div id="contents" style="height:500px;overflow:auto;"></div>
    <div>
        <textarea id="msg"></textarea>
        <a href="javascript:;" onclick="sendMsg()">發(fā)送</a>
    </div>
    <script src="{{static_url('js/jquery.min.js')}}"></script>
    <script type="text/javascript">
        var ws = new WebSocket("ws://192.168.114.177:8000/chat");
        ws.onmessage = function(e) {
            $("#contents").append("<p>" + e.data + "</p>");
        }
        function sendMsg() {
            var msg = $("#msg").val();
            ws.send(msg);
            $("#msg").val("");
        }
    </script>
</body>
</html>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容