WebSocket 是一種網絡通訊協議。RFC6455 定義了它的通訊標準。javascript
WebSocket 是 HTML5 開始提供的一種在單個 TCP 鏈接上進行全雙工通信的協議。html
瞭解計算機網絡協議的人,應該都知道:HTTP 協議是一種無狀態的、無鏈接的、單向的應用層協議。它採用了請求/響應模型。通訊請求只能由客戶端發起,服務端對請求作出應答處理。java
這種通訊模型有一個弊端:HTTP 協議沒法實現服務器主動向客戶端發起消息。python
這種單向請求的特色,註定了若是服務器有連續的狀態變化,客戶端要獲知就很是麻煩。大多數 Web 應用程序將經過頻繁的異步 JavaScript 和 XML(AJAX)請求實現長輪詢。輪詢的效率低,很是浪費資源(由於必須不停鏈接,或者 HTTP 鏈接始終打開)。web
所以,工程師們一直在思考,有沒有更好的方法。WebSocket 就是這樣發明的。WebSocket 鏈接容許客戶端和服務器之間進行全雙工通訊,以便任一方均可以經過創建的鏈接將數據推送到另外一端。WebSocket 只須要創建一次鏈接,就能夠一直保持鏈接狀態。這相比於輪詢方式的不停創建鏈接顯然效率要大大提升。json
Web 瀏覽器和服務器都必須實現 WebSockets 協議來創建和維護鏈接。因爲 WebSockets 鏈接長期存在,與典型的 HTTP 鏈接不一樣,對服務器有重要的影響。flask
基於多線程或多進程的服務器沒法適用於 WebSockets,由於它旨在打開鏈接,儘量快地處理請求,而後關閉鏈接。任何實際的 WebSockets 服務器端實現都須要一個異步服務器。api
在客戶端,沒有必要爲 WebSockets 使用 JavaScript 庫。實現 WebSockets 的 Web 瀏覽器將經過 WebSockets 對象公開全部必需的客戶端功能(主要指支持 Html5 的瀏覽器)。瀏覽器
如下 API 用於建立 WebSocket 對象。服務器
var Socket = new WebSocket(url, [protocol] );
屬性 | 描述 |
---|---|
Socket.readyState | 只讀屬性readySate表示鏈接狀態,能夠是如下值:0 - 表示鏈接還沒有創建,1 - 表示鏈接已創建,能夠進行通訊. 2 - 表示鏈接正在進行關閉.3 - 表示鏈接已經關閉或者鏈接不能打開 |
Socket.bufferedAmount | 只讀屬性 bufferedAmount 已被 send() 放入正在隊列中等待傳輸,可是尚未發出的 UTF-8 文本字節數。 |
事件 | 事件處理程序 | 描述 |
---|---|---|
open | Socket.onopen | 鏈接創建時觸發 |
message | Socket.onmessage | 客戶端接收服務端數據時觸發 |
error | Socket.onerror | 通訊發生錯誤時觸發 |
close | Socket.onclose | 鏈接關閉時觸發 |
WebSocket方法
方法 | 描述 |
---|---|
Socket.send() | 使用鏈接發送數據 |
Socket.close() | 關閉鏈接 |
# views.py from geventwebsocket.handler import WebSocketHandler from geventwebsocket.server import WSGIServer from geventwebsocket.websocket import WebSocket # 用於提示語法信息 from flask import Flask, request, render_template app = Flask(__name__) socket_list = [] @app.route('/ws') def ws(): sock = request.environ.get('wsgi.websocket') # type:WebSocket # request.environ是個大字典,獲取wsgi.websocket鍵對應的值即得到web.socket對象 socket_list.append(sock) while True: try: msg = sock.receive() # receive v.接收 except: socket_list.remove(sock) break # 監聽時若是鏈接異常會報錯,異常捕捉若是接收異常則刪除這個websocket對象 for so in socket_list: if so == sock: continue try: so.send(msg) except: continue # 若是發送的客戶端斷開則會報錯,捕捉異常,若是沒法正常發送則跳過 return '200 ok' @app.route('/') def index(): return render_template('wb_client.html') if __name__ == '__main__': http_serv = WSGIServer(('0.0.0.0', 9527), app, handler_class=WebSocketHandler) # app 是Flask示例化對象,wsgi處理完environ以後交給Flaskrequest處理.handler_class處理類型. http_serv.serve_forever()
websocket.html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3個meta標籤*必須*放在最前面,任何其餘內容都*必須*跟隨其後! --> <title>思宇羣聊</title> </head> <body> <input type="text" id="text"> <button id="send">點擊發送消息</button> <div id="content_list"></div> <script type='application/javascript'> var ws = new WebSocket('ws://192.168.14.118/ws') # 回調函數 # 鏈接創建時調用 ws.onopen = function() { ws.send('hello') } # 接收到消息時,執行 ws.onmessage = function (eventMessage) { var s = eventMessage.data; # 獲取數據 var p = document.createElement('p') p.innerText = s; document.getElementById('content_list').appendChild(p); }; # 綁定點擊事件發送消息 document.getElementById('send').addEventListener('onclick', function() { var st = document.getElementById('text').value; ws.send(st); }) </script> </body> </html>
# views.py import json from geventwebsocket.handler import WebSocketHandler # ws 協議請求處理 from geventwebsocket.server import WSGIServer # 替換Flask原有的WSGI from geventwebsocket.websocket import WebSocket from flask import Flask, request, render_template app = Flask(__name__) socket_dict = {} @app.route('/ws/<username>') def ws(username): sock = request.environ.get('wsgi.websocket', None) # type: WebSocket # 1.不是WS協議上的請求,則得到None # 2.WS協議認證失敗,得到None if not sock: return '請使用WS協議鏈接' socket_dict[username] = sock while True: msg = sock.receive() msg_dickt = json.loads(msg) recv = msg_dict.get('recv') recv_sock = socket_dict.get(recv) recv_sock.send(msg) @app.route('/') def index(): return render_template('ws_client_2.html') if __name__ == '__main__': http_serv = WSGIServer(('0.0.0.0', 9527),app, handler_class = WebSocketHandler) http.serv.serve.forever()
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Bootstrap 101 Template</title> </head> <body> 你的名字:<input type="text" id="username"><button id="createws">登陸聊天室</button> <p>給<input type="text" id="recv">發送<input type="text" id="text">內容 <button id="send">點擊發送消息</button></p> <div id="content_list"> </div> </body> <script type="application/javascript"> var ws = null; document.getElementById('createws').onclick = function() { # 獲取用戶名 var username = document.getElementById('username').value; ws = new WebSocket('ws://192.168.14.26:9527/ws/'+username); ws.onopen = function () { alert('歡迎進入九聊'); }; ws.onmessage = function (eventMessage) { var msg = JSON.parse(eventMessage.data); console.log(msg); var p = document.createElement('p'); p.insertText = msg.sender + ':' + msg.msg; document.getElementById('content_list').appendChild(p); }; }; </script> </html>
WebSocket協議 目前Workerman的WebSocke協議版本爲13 WebSocket protocol 是HTML5一種新的協議。它實現了瀏覽器與服務器全雙工通訊 WebSocket與TCP關係 WebSocket和HTTP同樣是一種應用層協議,都是基於TCP傳輸的,WebSocket自己和Socket並無多大關係,更不能等同。 WebSocket協議握手 WebSocket協議有一個握手的過程,握手時瀏覽器和服務端是以HTTP協議通訊的,在Workerman中能夠這樣介入到握手過程。