当使用websocket进行实时显示数据时,由于接收数据会阻塞线程,而此时await send_text(msg)
无法发送,如果在新的线程中调用发送,是无法调用await send_text()函数的,而如果在recv_text()后再发送,因为recive_text()会阻塞,致使之后服务器不断推送的数据无法发送,所以,经过多方尝试后,可以使用心跳的方式巧妙地实现不断的推送,在web浏览器端,不断的发送心跳,而在服务器端,当接收到的是心跳的信息后,跳过转发指令,直接读取数据。
如下:
服务端:
@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: str):
global manager
global isWhile
await manager.connect(client_id,websocket)
print("client %s: connected." % client_id)
try:
while True:
dataFromExplor = await manager.recivemessage(websocket) #从网页socket中获取到的值;
jsonData = json.loads(dataFromExplor) #json字符串解析成json对象;
if jsonData["cmd"] != "Heart.Beat": #若不是心跳,则需要将指令发送出去;通过心跳机制,以使recv不再完全阻塞,疏通了接收数据。
channelPacket = packetChannelData(client_id,jsonData,{}) #以 真实数据长度(4字节) + 真实数据(json字符串) 的格式进行封装;
manager.sendDataToWebServer(channelPacket) #通过管道将数据发送给TcpSocket线程;
await manager.trySendFromWebServer() #尝试接收返回的数据并发送回web浏览器客户端;
except WebSocketDisconnect:
print("client %s exit!" % client_id)
manager.disconnect(client_id,websocket)
客户端:
var ws
var timerId = -1
window.onload = function()
{
if(timerId >= 0){
window.clearInterval(timerId) //先关闭之前的定时器;
}
if ("WebSocket" in window){ //表明此浏览器支持 WebSocket!
// 打开一个 web socket;
var client_id = document.getElementById("username").value + "."+Date.now()
ws = new WebSocket(`ws://192.168.110.37:8001/ws/${client_id}`);
ws.onopen = function(){ //表明WebSocket已连接上;
//alert("连接成功!");
var cmdJson = {"cmd":"Fetch.Clients","params":{}}
ws.send(JSON.stringify(cmdJson))
timerId = self.setInterval("heartbeat()",100)
}
ws.onmessage = function(event){ //当服务器推送消息时,浏览器收到消息;
var msg = event.data
//alert(msg)
var obj = JSON.parse(msg)
var cmd = obj['query']['cmd']
var reply = obj['reply'] //jsonObject;
if(cmd == "Fetch.Clients"){
document.getElementById("client_ids").innerHTML = JSON.stringify(reply)
return;
}
if(cmd == "Session.Error"){
document.getElementById("session_errmsg").innerHTML = JSON.stringify(reply)
return ;
}
if(cmd == "Session.Status"){
document.getElementById("session_status").innerHTML = JSON.stringify(reply)
return ;
}
if(cmd == "Session.System"){
document.getElementById("session_sys").innerHTML = JSON.stringify(reply)
return ;
}
if(cmd == "Session.Zone"){
document.getElementById("session_zone").innerHTML = JSON.stringify(reply)
return ;
}
if(cmd == "Session.Alarm"){
document.getElementById("session_alarm").innerHTML = JSON.stringify(reply)
return ;
}
if(cmd == "Session.Profile"){
document.getElementById("session_profile").innerHTML = JSON.stringify(reply)
return ;
}
};
ws.onclose = function(){ //关闭WebSocket连接时,可以做些处理;
//alert("连接已关闭...");
if(timerId >= 0){
window.clearInterval(timerId) //先关闭之前的定时器;
}
};
}
else { // 浏览器不支持 WebSocket;
alert("您的浏览器不支持 WebSocket!");
}
}
function heartbeat(){
var cmdJson = {"cmd":"Heart.Beat","params":{}}
ws.send(JSON.stringify(cmdJson))
}