Я создаю веб-сервер торфа python3, который может прослушивать брокер MQTT и всякий раз, когда прослушивает новое сообщение от него, транслирует его в подключенные браузеры через веб-сокеты. Однако, похоже, что Tornado не нравится вызовы его API из потока, отличного от IOLoop.current (), и я не могу найти другое решение ...
Я уже пытался написать код. Я поместил весь клиент MQTT (в данном случае он называется клиентом PMCU) в отдельный поток, который зацикливается и прослушивает уведомления MQTT.
def on_pmcu_data(data):
for websocket_client in websocket_clients:
print("Sending websocket message")
websocket_client.write_message(data) # Here it stuck!
print("Sent")
class WebSocketHandler(tornado.websocket.WebSocketHandler):
def open(self):
websocket_clients.append(self)
def on_close(self):
websocket_clients.remove(self)
def make_app():
return tornado.web.Application([
(r'/ws', WebSocketHandler)
])
if __name__ == "__main__":
main_loop = IOLoop().current()
pmcu_client = PMCUClient(on_pmcu_data)
threading.Thread(target=lambda: pmcu_client.listen("5.4.3.2")).start()
app = make_app()
app.listen(8080)
main_loop.start()
Однако, как я уже сказал, кажется, что вызовы Tornado API вне блоков IOLoop.current (): приведенный выше код печатает только Sending websocket message
.
Мое намерение - запустить websocket_client.write_message(data)
в IOLoop.current()
цикле событий. Но похоже, что функция IOLoop.current().spawn_callback(lambda: websocket_client.write_message(data))
не работает после запуска IOLoop.current()
. Как мне этого добиться?
Я знаю, что у меня огромное недопонимание IOLoop, asyncio, от которого он зависит, и асинхронности python3.