用Python编写一个websocket客户端应用

前两天发了一篇《用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服务器。

好了,觉得这篇文章对你有帮助的话,请给我点个赞吧!

最后的最后,我在个人公众号“天飓”上建了一个#语音助手的合集,有兴趣的朋友欢迎关注和订阅^_^

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天飓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值