python:3.9.x
-case(功能代码模块文件夹)
--OutputPower.py(功能代码,接收到客户端信息,判断进入对应的功能模块)
-websocket(webSocket服务器代码,主要负责维护连接、接收数据、发送数据)
--server.py(服务器代码)
-app.py(程序入口)
server.py
功能包括:
1、建立websocket连接
2、收取客户端信息
3、发送客户端信息
此处我使用了多线程,主要是想到以后的功能模块交互问题
import asyncio
import websockets
import time
import json
import threading
# 功能模块
from case.OutputPower import OutputPower
# 存储所有的客户端
Clients = []
class Server():
# 发消息给客户端的回调函数
async def s(self,msg,websocket=None):
await self.sendMsg(msg,websocket)
# 针对不同的信息进行请求,可以考虑json文本
async def runCase(self,jsonMsg,websocket):
print('runCase')
# await OutputPower(jsonMsg,self.s,websocket)
op = OutputPower()
await op.run(jsonMsg,self.s,websocket)
# 每一个客户端链接上来就会进一个循环
async def echo(self,websocket, path):
Clients.append(websocket)
await websocket.send(json.dumps({"type": "handshake"}))
while True:
try:
recv_text = await websocket.recv()
message = "I got your message: {}".format(recv_text)
# 直接返回客户端收到的信息
await websocket.send(message)
print(message)
# 分析当前的消息 json格式,跳进功能模块分析
await self.runCase(jsonMsg='',websocket=websocket)
except websockets.ConnectionClosed:
print("ConnectionClosed...", path) # 链接断开
Clients.remove(websocket)
break
except websockets.InvalidState:
print("InvalidState...") # 无效状态
Clients.remove(websocket)
break
except Exception as e:
print(e)
Clients.remove(websocket)
break
# 发送消息
async def sendMsg(self,msg,websocket):
print('sendMsg:',msg)
if websocket != None:
await websocket.send(msg)
else:
await self.broadcastMsg(msg)
# 避免被卡线程
await asyncio.sleep(0.2)
# 群发消息
async def broadcastMsg(self,msg):
for user in Clients:
await user.send(msg)
# 启动服务器
async def runServer(self):
async with websockets.serve(self.echo, 'localhost', 8888):
await asyncio.Future() # run forever
# 多线程模式,防止阻塞主线程无法做其他事情
def WebSocketServer(self):
asyncio.run(self.runServer())
def startServer(self):
# 多线程启动,否则会堵塞
thread = threading.Thread(target=self.WebSocketServer)
thread.start()
thread.join()
print("go!!!")
做到业务分离(OutputPower.py)
import asyncio
class OutputPower():
async def run(self,arg,s,websocket):
# 发送消息方法,单独和请求的客户端发消息
await s('sssss', websocket)
# 群发消息
await s('起来hi')
(app.py)
from webSocket.server import Server
if __name__=='__main__':
s = Server()
s.startServer()
直接找一个在线的websocket进行连接测试即可,如 http://www.websocket-test.com/
结果如图:
12
I got your message:12
sssss
起来hi
起来hi
起来hi
于2022.7.13发现一个问题,由于我自己的业务处理时间很长,比如这样的
import asyncio
import time
class OutputPower():
def __init__(self):
self._stop = 0
async def stop(self):
self._stop = 1
print('i stop!')
async def run(self, arg, s, websocket):
k = 0
while 1:
time.sleep(2)
if self._stop == 1:
print('i jump out ...')
break
print('i am running ...')
k = k+1
if k== 10:
break
模拟业务处理:一直要处理20s完成这个业务,但是在开始后发现问题需要立刻停止这个业务,也就是self._stop==1
来停止这个业务,如果按照我们上面的设计,收到服务器的消息会就会一直进入 await op.run(jsonMsg,self.s,websocket)
业务,直到完成后才会走出这个业务,获得停止的命令,脱离了我们的初衷。
假定我们的协议都是json
格式:
开始任务:
{"type": 1}
结束任务
{"type": 2}
那么在页面上的交互逻辑,我直接截图来表达下流程:
步骤如下:
1、websocket建立连接,返回{\type\: \handshake\}
;
2、开始执行任务,下发:{"type": 1}
;
3、任务开始执行,返回正在执行的进度:i am running ... 0
;
4、任务没完成的时候,下发中止任务:{"type": 2}
;
5、任务中止,输出:stop!
。
其实这个做法有很多,我在这里就简单的说下我自己的原理:
1、websocket接收数据,缓存到全局变量queue中;
2、server处理增加线程读取这个queue,取出交互协议;
3、再次启动threading去处理该协议内容。
具体的代码可以见下方的测试代码。
见:https://download.csdn.net/download/weixin_44635546/85645105