如何在 tkinter 的线程中运行的 websocket 下发送消息?

Posted

技术标签:

【中文标题】如何在 tkinter 的线程中运行的 websocket 下发送消息?【英文标题】:How can I send a message down a websocket running in a thread from tkinter? 【发布时间】:2017-03-16 10:04:29 【问题描述】:

我有一个服务器脚本正在运行:

async def give_time(websocket,path):
    while True:
        await websocket.send(str(datetime.datetime.now()))
        await asyncio.sleep(3)

start_server = websockets.serve(give_time, '192.168.1.32', 8765)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

工作正常,只是每 3 秒发送一次当前时间。

我可以从运行此代码的客户端接收该字符串:

async def hello(): #takes whatever text comes through the websocket and displays it in the socket_text label.

    async with websockets.connect('ws://wilsons.lan:8765') as ws:
        while True:
            text = await ws.recv()
            logger.info('message received through websocket:'.format(text))
            socket_text.configure(text=text) #socket_text is a tkinter object

loop = asyncio.new_event_loop()

def socketstuff():
    asyncio.set_event_loop(loop)
    asyncio.get_event_loop().run_until_complete(hello())

t = threading.Thread(target=socketstuff,daemon=True)

它在一个线程中运行,这样我就可以在主线程中运行tkinter.mainloop。这是我第一次第一次使用threading,所以我可能弄错了,但目前它似乎有效。

我需要做的是能够基于 tkinter 事件通过 websocket 发送消息 - 目前只是单击文本框旁边的按钮,但最终会发生更复杂的事情。点击部分工作正常。

我在发送消息时遇到了很多麻烦。我尝试了很多不同的方法,有没有asyncawait,尽管那可能只是恐慌。

主要问题似乎是我无法从hello() 函数之外访问ws。这是有道理的,因为我正在使用with 上下文管理器。但是,如果我只使用ws = websockets.connect('ws://host'),那么我会得到一个websockets.py35.client.Connect object,当我尝试使用send(或者实际上是recv)方法时,我会得到一个object has no attribute 'send' 错误。

我希望这是足够的信息 - 很乐意发布任何其他需要的信息!

【问题讨论】:

再考虑问题,这里好像写错了。线程不是问题 - 我已经更改了它,以便 tkinter.mainloop() 在 asyncio 主循环中运行,所以现在不需要线程。但是,在上下文管理器之外访问 websocket 的问题仍然存在。我现在要尝试的是使用asyncio.queue 为tkinter 事件添加websocket 消息任务,并有一个从队列中取出它们并执行它们的asyncio 函数。如果可行,将发布答案! 【参考方案1】:

事实证明,解决这个问题的最佳方法是使用线程。

This post 帮我解决了。它表明您可以在协程中运行 tkinter 主循环的一个迭代:

async def do_gui(root,interval=0.05):
    while True:
        root.update()
        await asyncio.sleep(interval)

但是,让 tkinter 事件生成 websocket 消息的最佳方法是使用asyncio.queue。使 tkinter 回调使用put_nowait() 将项目添加到队列中,并有一个与do_gui 同时运行的协程,do_gui 使用await queue.get() 从队列中获取消息对我有用。

【讨论】:

以上是关于如何在 tkinter 的线程中运行的 websocket 下发送消息?的主要内容,如果未能解决你的问题,请参考以下文章

你如何在Tkinter的事件循环中运行自己的代码?

带有 pyserial RS232 的微型开关在 tkinter 线程中启动/停止计时器,但即使停止也继续运行

如何解决 Tkinter 中的多处理问题?

如何使用 tkinter 事件“继续”或暂停不同的 while 循环?

Tkinter 程序在 IDE (Visual Studio) 中运行良好,但是当使用 pyinstaller 编译为 .exe 时,线程的工作方式与在 IDE 中不同

树莓派、tkinter 和线程