鍍金池/ 教程/ Python/ 通過 python 和 websocket 構(gòu)建實時通信系統(tǒng)[擴展 saltstack 監(jiān)控]
通過 memcached 實現(xiàn)領號排隊功能及 python 隊列實例
利用 pypy 提高 python 腳本的執(zhí)行速度及測試性能
Python FAQ3-python 中 的原始(raw)字符串
Mongodb 千萬級數(shù)據(jù)在 python 下的綜合壓力測試及應用探討
Parallel Python 實現(xiàn)程序的并行多 cpu 多核利用【pp 模塊】
python simplejson 模塊淺談
服務端 socket 開發(fā)之多線程和 gevent 框架并發(fā)測試[python 語言]
python Howto 之 logging 模塊
python 之 MySQLdb 庫的使用
關于 python 調(diào)用 zabbix api 接口的自動化實例 [結(jié)合 saltstack]
python 之利用 PIL 庫實現(xiàn)頁面的圖片驗證碼及縮略圖
Python 通過 amqp 消息隊列協(xié)議中的 Qpid 實現(xiàn)數(shù)據(jù)通信
python 中用 string.maketrans 和 translate 巧妙替換字符串
python linecache 模塊讀取文件用法詳解
Python 批量更新 nginx 配置文件
python 計算文件的行數(shù)和讀取某一行內(nèi)容的實現(xiàn)方法
python+Django 實現(xiàn) Nagios 自動化添加監(jiān)控項目
多套方案來提高 python web 框架的并發(fā)處理能力
python 寫報警程序中的聲音實現(xiàn) winsound
python 調(diào)用 zabbix 的 api 接口添加主機、查詢組、主機、模板
對 Python-memcache 分布式散列和調(diào)用的實現(xiàn)
使用 python 構(gòu)建基于 hadoop 的 mapreduce 日志分析平臺
一個腳本講述 python 語言的基礎規(guī)范,適合初學者
Python 編寫的 socket 服務器和客戶端
如何將 Mac OS X10.9 下的 Python2.7 升級到最新的 Python3.3
python 監(jiān)控文件或目錄變化
報警監(jiān)控平臺擴展功能 url 回調(diào)的設計及應用 [python 語言]
Python 處理 cassandra 升級后的回滾腳本
python 實現(xiàn) select 和 epoll 模型 socket 網(wǎng)絡編程
關于 B+tree (附 python 模擬代碼)
通過 python 和 websocket 構(gòu)建實時通信系統(tǒng)[擴展 saltstack 監(jiān)控]

通過 python 和 websocket 構(gòu)建實時通信系統(tǒng)[擴展 saltstack 監(jiān)控]

先放一個小 demo~

用 html5 的 websocket 實現(xiàn)的聊天平臺。后端用的是 python bottle 框架。

后期要改成監(jiān)控,可能要聯(lián)合 saltstack 做實時的監(jiān)控。

像上篇博客說的那樣,實時監(jiān)控就那點東西,就是接收數(shù)據(jù)、顯示數(shù)據(jù) 。

像下面這樣:

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

http://wiki.jikexueyuan.com/project/python-actual-combat/images/8.png" alt="pic" />

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

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

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

WebSocket 的優(yōu)點

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

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

c)、不用頻率創(chuàng)建 TCP 請求及銷毀請求,減少網(wǎng)絡帶寬資源的占用,同時也節(jié)省服務器資源;

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

http://wiki.jikexueyuan.com/project/python-actual-combat/images/9.jpg" alt="pic" />

ws的連接狀態(tài):

GET /chat HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
Host: 66.xiaorui.cc:10000
Origin: http://66.xiaorui.cc
Cookie: somenterCookie

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

readyState 表示連接有四種狀態(tài):

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

url 是代表 WebSocket 服務器的網(wǎng)絡地址,協(xié)議通常是”ws”或“wss(加密通信)”,send 方法就是發(fā)送數(shù)據(jù)到服務器端;

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

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

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

我的后端代碼:

python 的后端實現(xiàn) websocket 的處理,有很多方法的。

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

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

后端的東西比較的簡單,就是把接收到的數(shù)據(jù),原路打回去。。。

我前端的代碼

這個是連接 webscoket,然后接收和發(fā)數(shù)據(jù)的 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>

用來呈現(xiàn)結(jié)果的 div

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

這里有個 tornado 后端的代碼,實現(xiàn)的過程和我差不多的~我需要的朋友可以跑一下~

import logging
import os.path
import uuid
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import tornado.websocket
def 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().start()
if __name__ == '__main__':
    main()

我和沈燦的對話~

http://wiki.jikexueyuan.com/project/python-actual-combat/images/10.jpg" alt="pic" />

沈燦和我的對話

http://wiki.jikexueyuan.com/project/python-actual-combat/images/11.jpg" alt="pic" />

本文出自 “峰云,就她了?!?博客,謝絕轉(zhuǎn)載!