前两天发了一篇《用Python做一个websocket服务端》,起了一个websocket服务。然后又发了一篇《用jquery做一个websocket客户端》,这是直接在网页中验证websocket服务是否有效。但是,对于客户端怎么实际应用websocket并没有涉及。作为一个轻微强迫症者,我觉得还是要再捣鼓一下websocket的客户端应用,于是便有了今天这篇。
在今天的这个示例中,我主要实现如下功能:
1.自动登录websocket服务器并完成握手(在服务器端完成注册);
2.接收服务器消息,若是收到指明发给自己的消息,则会在主线程打印,否则就忽略该消息;
3.接收到的消息中若有指定命令(如stat ==reply),便会回复消息。
注:在实验中,我就开了两个客户端,一个是网页版,一个是python版,在后面代码中你可以看到,我的客户端name是写死的。
先来看下效果图:
如上图,黑色背景的是python客户端,白色背景的是网页客户端。python端启动后自动连接websocket服务器并完成握手,client收到服务器发来的welcome;网页端和python端打招呼,发送smile消息,python端接收到这条消息后在主线程print;网页端向python端发送reply消息,python端接收后就回了一条smile消息给网页端;网页端向python端发送exit消息,python端断开连接。
python端的具体代码如下:
import asyncio
import threading
import websockets
import json
class wsClient(object):
def __init__(self):
super(wsClient, self).__init__()
self.uri = 'ws://127.0.0.1:9090'
self.stat = None
self.flag = False
self.msg = None
async def runClient(self):
try:
async with websockets.connect(self.uri) as websocket:
print("websocket 连接成功!")
msg = json.dumps({"stat": "link", "to": "", "content": "", "from": "core"})
await websocket.send(msg)
try:
while True:
if self.flag:
message = json.dumps({"stat": self.stat, "to": "ui", "content": self.msg, "from": "core"})
await websocket.send(message)
print("send a message")
self.flag = False
else:
result = await websocket.recv()
print(f"Received:{result}")
resp = json.loads(result)
receiver = resp['to']
stat = resp['stat']
if receiver == 'core':
self.stat = stat
await asyncio.sleep(0.2)
except Exception as e:
print("WS连接异常关闭:")
print(e)
except Exception as e:
print("重连失败:")
print(e)
def getStat(self):
return self.stat
def setAttr(self, stat, msg, flag):
self.stat = stat
self.msg = msg
self.flag = flag
# 定义一个专门创建事件循环loop的函数,在另一个线程中启动它
def start_loop(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
client = wsClient()
coroutine1 = client.runClient()
new_loop = asyncio.new_event_loop()
t = threading.Thread(target=start_loop, args=(new_loop,), daemon=True)
t.start()
task = asyncio.run_coroutine_threadsafe(coroutine1, new_loop)
flag = True
tp = None
while flag:
stat = client.getStat()
if stat != tp:
print(stat)
tp = stat
if stat == 'reply':
client.setAttr('smile', 'hello', True)
elif stat == 'exit':
flag = False
如上代码,我分成了上下两部分,上半部分是定义了一个class,下半部分又可以分成两段,第一段是生成一个子线程,让websocket client在子线程里跑。第二段则是主线程业务操作,读取class中的stat并以此作为判断依据执行任务。
好了,如何用python编写一个websocket客户端应用就到这儿了。
再说下之前那篇 《用Python做一个websocket服务端》代码中的一个bug,就是当服务器和某个客户端断开连接后,我没有删除Client队列中对应的数据项,这会导致其他客户端再发消息时就报错了。这个bug的解决就是添加一段从Client队列remove断线client信息,具体代码如下:
先定义一个获取对应下线客户端在Client中id的函数。
# 从队列中清除已下线client
def getClientIndex(self, websocket):
num = 0
index = None
for user in Clients:
if user['socket'] == websocket:
index =num
num += 1
return index
然后删除对应client。
index = self.getClientIndex(websocket)
if index is not None:
Clients.remove(Clients[index])
因为断开连接有三种状态,所以需要在每一种断开状态的时候把上面这上端删除client的代码放进去。这样的话,当一个客户端断线了,其他客户端不会受到影响,还能继续正常连接websocket服务器。
好了,觉得这篇文章对你有帮助的话,请给我点个赞吧!
最后的最后,我在个人公众号“天飓”上建了一个#语音助手的合集,有兴趣的朋友欢迎关注和订阅^_^
标签:stat,websocket,Python,self,python,loop,客户端 From: https://blog.csdn.net/hydekong/article/details/143903990