WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。HTML5 WebSocket 设计出来的目的就是要取代轮询和 Comet 技术,使客户端浏览器具备像 C/S 架构下桌面系统的实时通讯能力。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
我们知道http是短连接的,反复建立和销毁连接比较耗费资源,另外http协议经常头部内容比主体内容还长也比较浪费资源;websocket可以认为就是一个内容使用载荷固定格式的socket长连接。
请求格式和 HTTP 请求很相似,但是还是稍有不同。
请求信息:
1、“Upgrade:WebSocket”:表示这是一个特殊的 HTTP 请求,请求的目的就是要将客户端和服务器端的通讯协议从 HTTP 协议升级到 WebSocket 协议。
2、“Sec-WebSocket-Key”:客户端浏览器需要向服务器端提供的握手信息。
应答消息:
1、“Upgrade:WebSocket”:同请求消息。
2、“Sec-WebSocket-Accept”:服务器端解析这些头信息,并在握手的过程中依据这些信息生成一个 16 位的安全密钥并返回给客户端,以表明服务器端获取了客户端的请求,同意创建 WebSocket 连接。一旦连接建立,客户端和服务器端就可以通过这个通道双向传输数据了。
首先安装websocket-client-py3模块:
pip install websocket-client-py3
长连接关键方法:
ws.run_forever()
python的仿js websocket写法方式,自动重连发送指令,连接时间明显减少,基本做到无遗漏数据,与HTML js的ws连接实现一样。
import websocket
from websocket import ABNF
import json
import _thread
import time
def on_message(ws, message):
print(message)
def on_error(ws, error):
print(error)
def on_close(ws):
print("close connection")
def on_open(ws):
def run(*args):
pass
# content = {
# "mid": "1508232047195",
# "version": "1.0",
# "request": {
# "timestamp": 1508232047195,
# "sessionId": "aaaadsfasdfkop"
# },
# "params": {
# "audio": {
# "audioType": "wav",
# "sampleRate": 16000,
# "channel": 1,
# "sampleBytes": 2
# }
# }
# }
# ws.send(json.dumps(content))
# step = 3200
# with open(wav_path, 'rb') as f:
# while True:
# read_data = f.read(step)
# if read_data:
# ws.send(read_data, ABNF.OPCODE_BINARY)
# if len(read_data) < step:
# break
# time.sleep(0.1)
#
# ws.send('', ABNF.OPCODE_BINARY)
# time.sleep(1.5)
# ws.close()
# _thread.start_new_thread(run, ())
if __name__ == "__main__":
websocket.enableTrace(True)
ws = websocket.WebSocketApp(url='ws://10.201.7.239:8063/sml/ws/log/646',
on_message=on_message,
on_error=on_error,
on_close=on_close)
ws.on_open = on_open
ws.run_forever()
关键方法:
ws.recv()
ws.recv_data()
查看打印结果,丢失了很多日志数据,因此建议使用长连接的调用方式。
import websocket
while True:
ws = websocket.WebSocket()
#建立websocket连接,这里传入了 header ,需要注意header的写入方式
ws.connect("ws://10.201.7.239:8063/sml/ws/log/646",
# header=["Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits",
# # "Sec-WebSocket-Key: 8OnwGkJ1ac82cI3g/q/WNA==",
# "Sec-WebSocket-Version: 13",
# "Upgrade: websocket"]
)
if ws.connected:
print("websocket connected", "."*30)
#接收实时数据,并打印出来
while ws.recv():
opcode, data = ws.recv_data()
print(data.decode('utf-8'))
# #关闭连接
ws.close()
break
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>websocket通信客户端</title>
<style>
#baseText {
background: black;
color: green;
}
</style>
<script type="text/javascript">
function WebSocketTest()
{
var received_msg = '';
if ("WebSocket" in window)
{
// 打开一个 web socket
var ws = new WebSocket("ws://10.201.7.239:8063/sml/ws/log/646");
// 连接建立后的回调函数
ws.onopen = function()
{
// Web Socket 已连接上,使用 send() 方法发送数据
};
// 接收到服务器消息后的回调函数
ws.onmessage = function (evt)
{
received_msg = received_msg + evt.data;
$('#baseText').html(received_msg);
};
// 连接关闭后的回调函数
ws.onclose = function()
{
// 关闭 websocket
ws.close();
alert("连接已关闭...");
};
}
else
{
// 浏览器不支持 WebSocket
alert("您的浏览器不支持 WebSocket!");
}
}
</script>
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
</head>
<body>
<textarea id="baseText" style="width: 800px; height: 800px; margin: 0px;"></textarea><br>
<input type="button" onclick="WebSocketTest()" value="获取组件日志打印">
</body>
</html>
使用过滤器表达式“websocket”过滤wireshark拦截数据包:
追踪数据流可以清晰看清websocket通信过程,首先使用http建立连接,然后升级到了websocket协议。
再看具体数据流也确实如此,先用两个http包建立连接,而后是websocket通信(问题是不清楚websocket内容是怎么编码的,有些就显示不了原始内容)
参考:
https://www.cnblogs.com/lsdb/p/10949766.html
https://blog.csdn.net/julia922/article/details/89334200