用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服务器。

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

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

<think>好的,用户想用Python一个WebSocket客户端给Artisan烘豆软件传输温度数据。首先,我需要确认Artisan软件是否支持WebSocket服务器,或者有没有公开的API文档。通常这类软件可能需要特定的协议或端口,用户可能需要先查阅Artisan的文档或社区资源。 假设Artisan已经配置好WebSocket服务器,监听某个端口,比如localhost:8080。接下来,我需要选择PythonWebSocket库。常用的有websockets和websocket-client。websockets支持异步,适合高频通信,而websocket-client是同步的,可能更简单。用户可能需要根据环境选择,这里假设用websocket-client库。 然后,安装库,使用pip install websocket-client。接下来,编写连接代码。需要处理on_open、on_message等事件。在on_open回调里发送温度数据,可能要按照Artisan指定的格式,比如JSON包含timestamp和temperature字段。 用户可能需要知道如何生成或获取实时温度数据。这里可能需要模拟数据,比如随机生成。同时,发送频率要合适,比如每秒一次,避免过高负载。还要处理可能的异常,比如连接失败、断开重连等。 代码结构大致是:导入库,定义回调函数,建立连接,然后运行。需要注意的是,WebSocket的URL是否正确,是否有认证参数,比如ws://localhost:8080/path?key=value。用户可能需要根据实际情况修改URL。 另外,确保数据格式符合Artisan的要求,可能需要参考其文档,比如特定的键名或数据结构。如果Artisan使用其他协议,比如HTTP轮询或MQTT,可能需要调整方法。但用户明确提到WebSocket,所以先按这个来。 最后,测试连接,检查Artisan是否接收到数据。如果出现问题,需要调试连接、数据格式或端口权限等问题。可能还需要日志记录和错误处理,确保客户端稳定运行。</think>要使用Python编写WebSocket客户端向Artisan烘焙软件传输温度数据,可以按照以下步骤实现: 1. **确认Artisan配置**: - 确保Artisan已开启WebSocket服务(默认端口通常为8080) - 在Artisan设置中启用远程数据接口(需参考Artisan文档) 2. **安装依赖库**: ```bash pip install websocket-client ``` 3. **基础客户端代码**: ```python import websocket import json import time class ArtisanClient: def __init__(self, url="ws://localhost:8080"): self.ws = websocket.WebSocketApp( url, on_open=self.on_open, on_message=self.on_message, on_error=self.on_error, on_close=self.on_close ) def on_open(self, ws): print("连接已建立") def on_message(self, ws, message): print(f"收到消息: {message}") def on_error(self, ws, error): print(f"发生错误: {error}") def on_close(self, ws, close_status_code, close_msg): print("连接已关闭") def send_temperature(self, bt, et): """发送豆温/环境温度数据""" data = { "type": "temperature", "bt": bt, # 豆温(Bean Temperature) "et": et # 环境温度(Environmental Temperature) } self.ws.send(json.dumps(data)) def run(self): self.ws.run_forever() if __name__ == "__main__": client = ArtisanClient() # 模拟温度数据发送 try: client.run() for i in range(10): bt = 180 + i*2 # 模拟豆温上升 et = 160 + i # 模拟环境温度 client.send_temperature(bt, et) time.sleep(1) except KeyboardInterrupt: client.ws.close() ``` 4. **关键点说明**: - 数据格式需要符合Artisan的协议规范(需参考官方文档) - 温度单位默认使用摄氏度(需与Artisan设置一致) - 推荐发送频率:1-2秒/次 - 实际应用需添加异常处理和重连机制 5. **增强功能建议**: ```python # 添加重连机制 def run_forever(self, retry=3): while retry > 0: try: self.ws.run_forever() except Exception as e: print(f"连接异常,剩余重试次数 {retry}") retry -= 1 time.sleep(5) # 添加数据校验 def validate_temperature(self, temp): if not (50 <= temp <= 250): raise ValueError("温度值超出合理范围") return round(temp, 1) ``` 注意: 1. 实际使用时需根据Artisan的API文档调整数据格式 2. 可能需要配置Artisan的访问控制白名单 3. 建议使用SSL加密连接(wss://)进行生产环境通信 4. 温度数据建议包含时间戳字段 可以通过Wireshark或Artisan的调试界面验证数据是否成功接收。如果遇到连接问题,请检查防火墙设置和Artisan的WebSocket服务状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

天飓

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

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

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

打赏作者

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

抵扣说明:

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

余额充值