Python3+WebSockets實現WebSocket通訊

1、說明

1.1 背景說明

前段時間同事說雲平臺通訊使用了個websocket的東西,今天抽空來看一下具體是怎麼個通訊過程。javascript

從形式上看,websocket是一個應用層協議,socket是數據鏈路層、網絡層、傳輸層的抽像;從應用場合上看,websocket可使用javascript實現,而socket不能用javascript實現(真不能嗎?我不太肯定);從實際效果上看,和通常的socket鏈接用起來沒什麼區別。html

咱們知道http是短鏈接的,反覆創建和銷燬鏈接比較耗費資源,另外http協議常常頭部內容比主體內容還長也比較浪費資源;websocket能夠認爲就是一個內容使用載荷固定格式的socket長鏈接。html5

websocket基本協議格式以下,更多說明見RFC 6455java

 

1.2 環境說明

當前環境我使用Python3+WebSockets庫,WebSockets直接使用pip安裝便可:python

pip install websockets

 

2、代碼實現

長鏈接是有狀態的,因此通常在且只在最開始進行一次身份認證,然後通訊過程不須要認證信息。咱們這裏實現一個簡單的用戶名密碼認證過程。長鏈接更多內容可參考「鏈接與短鏈接的安全差別討論 」。git

另外,注意把代碼中的ip改爲本身的。github

 

2.1 python服務端代碼

import asyncio import websockets # 檢測客戶端權限,用戶名密碼經過才能退出循環
async def check_permit(websocket): while True: recv_str = await websocket.recv() cred_dict = recv_str.split(":") if cred_dict[0] == "admin" and cred_dict[1] == "123456": response_str = "congratulation, you have connect with server\r\nnow, you can do something else" await websocket.send(response_str) return True else: response_str = "sorry, the username or password is wrong, please submit again" await websocket.send(response_str) # 接收客戶端消息並處理,這裏只是簡單把客戶端發來的返回回去
async def recv_msg(websocket): while True: recv_text = await websocket.recv() response_text = f"your submit context: {recv_text}" await websocket.send(response_text) # 服務器端主邏輯 # websocket和path是該函數被回調時自動傳過來的,不須要本身傳
async def main_logic(websocket, path): await check_permit(websocket) await recv_msg(websocket) # 把ip換成本身本地的ip
start_server = websockets.serve(main_logic, '10.10.6.91', 5678) # 若是要給被回調的main_logic傳遞自定義參數,可以使用如下形式 # 1、修改回調形式 # import functools # start_server = websockets.serve(functools.partial(main_logic, other_param="test_value"), '10.10.6.91', 5678) # 修改被回調函數定義,增長相應參數 # async def main_logic(websocket, path, other_param)
 asyncio.get_event_loop().run_until_complete(start_server) asyncio.get_event_loop().run_forever()

 

2.2 python版客戶端代碼

import asyncio import websockets # 向服務器端認證,用戶名密碼經過才能退出循環
async def auth_system(websocket): while True: cred_text = input("please enter your username and password: ") await websocket.send(cred_text) response_str = await websocket.recv() if "congratulation" in response_str: return True # 向服務器端發送認證後的消息
async def send_msg(websocket): while True: _text = input("please enter your context: ") if _text == "exit": print(f'you have enter "exit", goodbye') await websocket.close(reason="user exit") return False await websocket.send(_text) recv_text = await websocket.recv() print(f"{recv_text}") # 客戶端主邏輯
async def main_logic(): async with websockets.connect('ws://10.10.6.91:5678') as websocket: await auth_system(websocket) await send_msg(websocket) asyncio.get_event_loop().run_until_complete(main_logic())

 

2.3 html版客戶端代碼

html版客戶端代碼,只能經過回調函數接收服務端返回的數據,不能主動接收,感受怪怪的。web

<!DOCTYPE HTML>
<html>
   <head>
   <meta charset="utf-8">
   <title>websocket通訊客戶端</title>
       <script type="text/javascript">
         function WebSocketTest() { if ("WebSocket" in window) { // 打開一個 web socket
               var ws = new WebSocket("ws://10.10.6.91:5678"); // 鏈接創建後的回調函數
 ws.onopen = function() { // Web Socket 已鏈接上,使用 send() 方法發送數據
 ws.send("admin:123456"); alert("正在發送:admin:123456"); }; // 接收到服務器消息後的回調函數
 ws.onmessage = function (evt) { var received_msg = evt.data; if (received_msg.indexOf("sorry") == -1) { alert("收到消息:"+received_msg); } }; // 鏈接關閉後的回調函數
 ws.onclose = function() { // 關閉 websocket
 alert("鏈接已關閉..."); }; } else { // 瀏覽器不支持 WebSocket
 alert("您的瀏覽器不支持 WebSocket!"); } } </script>
   </head>

   <body onload="WebSocketTest()">

   </body>
</html>
View Code

 

3、通訊數據包截獲及通訊過程分析

如下數據包其於上邊的python服務端和html版客戶端,再次強調注意把代碼中的ip改爲本身電腦當前的ip。瀏覽器

 

3.1 wireshark通訊數據包截獲及通訊過程分析

wireshark攔截數據包後可以使用過濾器表達式「websocket」進行過濾:安全

咱們追蹤數據流能夠更清晰地看清websocket的通訊過程,能夠看到先是用http完成了創建鏈接,而後切換到websocket協議。

 再看具體數據流也確實如此,先用兩個http包創建鏈接,然後是websocket通訊(問題是不清楚websocket內容是怎麼編碼的,有些就顯示不了原始內容)

 

3.2 burpsuite通訊數據包截獲及通訊過程分析

和正常配置代理便可,burpsuite能識別和攔截websocket數據包,以下圖:

不過和通常http請求有區別的是,websocket請求會被單獨彙總到「WebSockets history」選項卡,而不是和http請求混在「HTTP history」選項卡。

 

3.3 開發者工具通訊數據包截獲及通訊過程分析

Firefox開發者工具只能看到創建websocket鏈接的兩個http數據包,沒看到怎麼查看具體傳輸內容,Chrome開發者工具Frames選項卡能夠,以下:

 

參考:

https://websockets.readthedocs.io/en/stable/intro.html

https://www.runoob.com/html/html5-websocket.html

https://github.com/aaugustin/websockets/issues/271

相關文章
相關標籤/搜索