websocket和http
websocket是HTML5開始提供的一種在單個TCP連接上進行全雙工通訊的協議.
websocket使得客戶端和服務器之間的數據交換變得更加簡單, 允許服務端主動向客戶端推送數據.
在websocket API中, 瀏覽器和服務器只需要完成一次握手, 兩者之間就可以直接創建持久性的連接, 並進行雙向數據傳輸.
在websocket API中, 瀏覽器和服務器只需要做一個握手的動作, 然后, 瀏覽器和服務器之間就形成了一條快速通道. 兩者之間就直接可以數據互相傳送.
當下很多網站為了實現推送技術, 所用的技術都是Aiax輪詢. 輪詢是在特定的時間間隔, 有瀏覽器對服務器發出HTTP請求, 然后由服務器返回最新的數據給客戶端的瀏覽器. 這種傳統的模式帶來很明顯的缺點, 即瀏覽器需要不斷地向服務器發出請求, 然而HTTP請求可能包含較長的頭部, 其中真正有效的數據可能只是很小的一部分, 這樣會浪費很多的帶寬等資源.
HTML5定義的websocket協議, 能更好的節省服務器資源和帶寬, 並且能都更實時的進行通訊.

瀏覽器通過JavaScript向服務器發出建立websocket連接的請求, 連接建立以后, 客戶端和服務器可以通過TCP連接直接交換數據.
當獲取websocket連接后, 可以通過send()方法來向服務器發送數據, 並通過onmessage事件來接收服務器返回的數據.
# 創建WebSocket對象 var Socket = new WebSocket(url, [protocol] ); # 第一個參數 url, 指定連接的 URL。第二個參數 protocol 是可選的,指定了可接受的子協議
WebSocket屬性 :
| 屬性 | 描述 |
| Socket.readyState | 只讀屬性readyState表示連接狀態, 可以是以下值 : |
| 0 - 表示連接尚未建立 | |
| 1 - 表示連接已建立, 可以進行通信 | |
| 2 - 表示連接正在進行關閉 | |
| 3 - 表示連接已經關閉或者連接不能打開 | |
| Socket.bufferedAmount | 只讀屬性 bufferedAmount已被send()放入正在隊列中等待傳輸, 但是還沒有發出的UTF-8文本字節數. |
WebSocket事件 :
| 事件 | 事件處理程序 | 描述 |
| open | Socket.onopen | 連接建立時觸發 |
| message | Socket.onmessage | 客戶端接收服務端數據時觸發 |
| error | Socket.onerror | 通信發生錯誤時觸發 |
| close | Socket.onclose | 連接關閉時觸發 |
多人聊天
建議使用火狐瀏覽器.
html頁面 :
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <p>發送內容: <input type="text" id="send_msg"><button onclick="send()">發送消息</button></p> <!--用於顯示聊天記錄的div--> <div id="msg_list" style="width: 500px"></div> </body> <script> var ws = new WebSocket("ws://192.168.12.61:5000/ws"); ws.onmessage = function (ws_status) { console.log(ws_status.data); var ptag = document.createElement("p"); ptag.innerText = ws_status.data; document.getElementById("msg_list").appendChild(ptag) }; function send() { var msg = document.getElementById("send_msg").value; <!--創建一個p標簽--> var ptag = document.createElement("p"); <!--給標簽加css屬性--> ptag.style.cssText = "text-align: right"; <!--給p標簽添加內容--> ptag.innerText = msg; <!--在div內加p標簽--> document.getElementById("msg_list").appendChild(ptag); ws.send(msg); } </script> </html>
后端代碼 :
from flask import Flask, request, render_template from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import WSGIServer app = Flask(__name__) # type:Flask # 存放接連用戶的列表 user_socket_list = [] @app.route("/ws") def ws(): """ 將連接的用戶加入到user_socket_list列表內 對列表循環, 將發送者發送的消息返給連接的用戶(除了自己) :return: """ # 獲取連接的用戶 user_socket = request.environ.get("wsgi.websocket") if user_socket: user_socket_list.append(user_socket) while 1: # 接收發送消息者發送的消息 msg = user_socket.receive() print(msg) # 此時user_socket是發送消息者 for usocket in user_socket_list: # 排除列表內發送消息者 if user_socket == usocket: continue try: # 對每一個除了自己以外的連接者發送消息 usocket.send(msg) except: continue @app.route("/") def index(): return render_template("ws.html") if __name__ == '__main__': http_serv = WSGIServer(("0.0.0.0", 5000), app, handler_class=WebSocketHandler) http_serv.serve_forever()
