讀古今文學網 > Python實戰-從菜鳥到大牛的進階之路 > 10 通過 python 和 websocket 構建實時通信系統[擴展 saltstack 監控] >

10 通過 python 和 websocket 構建實時通信系統[擴展 saltstack 監控]

先放一個小 demo~

用 html5 的 websocket 實現的聊天平台。後端用的是 python bottle 框架。

後期要改成監控,可能要聯合 saltstack 做實時的監控。

像上篇博客說的那樣,實時監控就那點東西,就是接收數據、顯示數據 。

像下面這樣:

原文地址:http://rfyiamcool.blog.51cto.com/1030776/1269232

圖片 10.1 pic

WebSocket API 是下一代客戶端-服務器的異步通信方法。該通信取代了單個的 TCP 套接字,使用 ws 或 wss 協議,可用於任意的客戶端和服務器程序。

WebSocket 目前由 W3C 進行標準化。WebSocket 已經受到 Firefox 4、Chrome 、Opera 10.70 以及 Safari 5 等瀏覽器的支持。

WebSocket API最偉大之處在於服務器和客戶端可以在給定的時間範圍內的任意時刻,相互推送信息。WebSocket 並不限於以 Ajax(或 XHR)方式通信,因為 Ajax 技術需要客戶端發起請求,而 WebSocket 服務器和客戶端可以彼此相互推送信息;XHR 受到域的限制,而 WebSocket 允許跨域通信。

WebSocket 的優點

a)、服務器與客戶端之間交換的標頭信息很小,大概只有 2 字節;

b)、客戶端與服務器都可以主動傳送數據給對方;

c)、不用頻率創建 TCP 請求及銷毀請求,減少網絡帶寬資源的佔用,同時也節省服務器資源;

建立連接的握手  當 Web 應用程序調用 new WebSocket(url)接口時,Browser 就開始了與地址為 url 的 WebServer 建立握手連接的過程。1. Browser 與 WebSocket 服務器通過 TCP 三次握手建立連接,如果這個建立連接失敗,那麼後面的過程就不會執行,Web應用程序將收到錯誤消息通知。2. 在 TCP 建立連接成功後,Browser/UA 通過 http 協議傳送 WebSocket 支持的版本號,協議的字版本號,原始地址,主機地址等等一些列字段給服務器端。3. WebSocket 服務器收到 Browser/UA 發送來的握手請求後,如果數據包數據和格式正確,客戶端和服務器端的協議版本號匹配等等,就接受本次握手連接,並給出相應的數據回復,同樣回復的數據包也是採用 http 協議傳輸。4. Browser 收到服務器回復的數據包後,如果數據包內容、格式都沒有問題的話,就表示本次連接成功,觸發 onopen 消息,此時 Web 開發者就可以在此時通過 send 接口想服務器發送數據。否則,握手連接失敗,Web 應用程序會收到 onerror 消息,並且能知道連接失敗的原因。這個握手很像 HTTP,但是實際上卻不是,它允許服務器以 HTTP 的方式解釋一部分 handshake 的請求,然後切換為 websocket數據傳輸WebScoket 協議中,數據以幀序列的形式傳輸。考慮到數據安全性,客戶端向服務器傳輸的數據幀必須進行掩碼處理。服務器若接收到未經過掩碼處理的數據幀,則必須主動關閉連接。服務器向客戶端傳輸的數據幀一定不能進行掩碼處理。客戶端若接收到經過掩碼處理的數據幀,則必須主動關閉連接。針對上情況,發現錯誤的一方可向對方發送 close 幀(狀態碼是 1002,表示協議錯誤),以關閉連接。  

圖片 10.2 pic

ws的連接狀態:

GET /chat HTTP/1.1Upgrade: WebSocketConnection: UpgradeHost: 66.xiaorui.cc:10000Origin: http://66.xiaorui.ccCookie: somenterCookie  

簡單瞭解下接口方法和屬性:

readyState 表示連接有四種狀態:

  • CONNECTING (0):表示還沒建立連接;
  • OPEN (1): 已經建立連接,可以進行通訊;
  • CLOSING (2):通過關閉握手,正在關閉連接;
  • CLOSED (3):連接已經關閉或無法打開;

url 是代表 WebSocket 服務器的網絡地址,協議通常是」ws」或「wss(加密通信)」,send 方法就是發送數據到服務器端;

close 方法就是關閉連接;
onopen 連接建立,即握手成功觸發的事件;
onmessage 收到服務器消息時觸發的事件;
onerror 異常觸發的事件;
onclose 關閉連接觸發的事件;

來個例子,咱們用 js 來搞搞

var wsServer = \'ws://localhost:8888/Demo\'; //服務器地址var websocket = new WebSocket(wsServer); //創建 WebSocket 對像websocket.send("hello");//向服務器發送消息alert(websocket.readyState);//查看 websocket 當前狀態websocket.onopen = function (evt) {    //已經建立連接};websocket.onclose = function (evt) {    //已經關閉連接};websocket.onmessage = function (evt) {    //收到服務器消息,使用 evt.data 提取};websocket.onerror = function (evt) {    //產生異常};  

我的後端代碼:

python 的後端實現 websocket 的處理,有很多方法的。

比較常見的是 gevent 的 websocket 的方式。

from bottle import get, run, templatefrom bottle.ext.websocket import GeventWebSocketServerfrom bottle.ext.websocket import websocketimport geventusers = set@get(\'/\')def index:    return template(\'index\')@get(\'/websocket\', apply=[websocket])def chat(ws):    users.add(ws)    while True:msg = ws.receiveif msg is not None:    for u in users:print type(u)u.send(msg)print u,msgelse: break    users.remove(ws)run(host=\'10.10.10.66\', port=10000, server=GeventWebSocketServer) 

後端的東西比較的簡單,就是把接收到的數據,原路打回去。。。

我前端的代碼

這個是連接 webscoket,然後接收和發數據的 js

<script>$(document).ready(function {    if (!window.WebSocket) {if (window.MozWebSocket) {    window.WebSocket = window.MozWebSocket;} else {    $(\'#messages\').append("<li>Your browser doesn\'t support WebSockets.</li>");}    }    ws = new WebSocket(\'ws://10.10.10.66:10000/websocket\');    ws.onopen = function(evt) {$(\'#messages\').append(\'<li>Connected to chat.</li>\');    }    ws.onmessage = function(evt) {$(\'#messages\').append(\'<li>\' + evt.data + \'</li>\');    }    $(\'#send-message\').submit(function {ws.send($(\'#name\').val + ": " + $(\'#message\').val);$(\'#message\').val(\'\').focus;return false;    });});    </script>  

用來呈現結果的 p

form id="send-message" class="form-inline"><input id="name" type="text" value="可以更換名字"><input id="message" type="text" value="要扯淡的內容" />       &nbsp; <button class="btn btn-success" type="submit">Send</button>    </form>    <p id="messages"></p>  

這裡有個 tornado 後端的代碼,實現的過程和我差不多的~我需要的朋友可以跑一下~

import loggingimport os.pathimport uuidimport tornado.httpserverimport tornado.ioloopimport tornado.optionsimport tornado.webimport tornado.websocketdef send_message(message):    for handler in ChatSocketHandler.socket_handlers:try:    handler.write_message(message)except:    logging.error(\'Error sending message\', exc_info=True)class MainHandler(tornado.web.RequestHandler):    def get(self):self.render(\'index.html\')class ChatSocketHandler(tornado.websocket.WebSocketHandler):    socket_handlers = set    def open(self):ChatSocketHandler.socket_handlers.add(self)send_message(\'A new user has entered the chat room.\')    def on_close(self):ChatSocketHandler.socket_handlers.remove(self)send_message(\'A user has left the chat room.\')    def on_message(self, message):send_message(message)def main:    settings = {\'template_path\': os.path.join(os.path.dirname(__file__), \'templates\'),\'static_path\': os.path.join(os.path.dirname(__file__), \'static\')    }    application = tornado.web.Application([(\'/\', MainHandler),(\'/new-msg/\', ChatHandler),(\'/new-msg/socket\', ChatSocketHandler)    ], **settings)    http_server = tornado.httpserver.HTTPServer(application)    http_server.listen(8000)    tornado.ioloop.IOLoop.instance.startif __name__ == \'__main__\':    main  

我和沈燦的對話~

圖片 10.3 pic

沈燦和我的對話

圖片 10.4 pic

本文出自 「峰雲,就她了。」 博客,謝絕轉載!