Следующая ситуация:
- Веб-клиент: использование JavaScript
socketio
для прослушивания входящих сообщений (= JavaScript).
- Веб-сервер: использование
flask-socketio
с eventlet
для отправки данных (= Python).
Все работает, если клиент отправляет сообщение на сервер. Сервер получает сообщения. Пример:
socketio = SocketIO(app, engineio_logger=True, async_mode="eventlet")
@socketio.on("mymsg")
def handle_event(message):
print("received message: " + str(message))
К сожалению, наоборот не работает - до некоторой степени. У меня есть поток, выдающий живые данные примерно 5-10 раз в секунду, который должен отображать веб-интерфейс. Он должен быть отправлен клиенту.
Во-первых: он вообще не работает, если поток, производящий данные, пытается вызвать sockeito.emit()
напрямую. Причина этого неясна для меня, но как-то правдоподобно, поскольку flask-socketio
с eventlet
следует различным асинхронным моделям, как говорится в документации.
Второе: отделение классических потоков от асинхронной модели флешки / эвентлета работает до некоторой степени. Я пытаюсь использовать для этого очередь eventlet
. Все данные о состоянии, которые генерирует мой поток, помещаются в очередь следующим образом:
statusQueue.put(statusMsg)
Это отлично работает. Сообщения отладки показывают, что это выполняется все время, добавляя данные за данными в очередь.
Как сказано в документации к колбам, рекомендуется использовать socketio.start_background_task()
, чтобы получить работающую "нить" в режиме, совместимом с асинхронной моделью socketio
. Поэтому я использую этот код:
def emitStatus():
print("Beginning to emit ...")
while True:
msg = statusQueue.get()
print("Sending status packet: " + str(msg))
socketio.emit("status", msg, broadcast=True)
statusQueue.task_done()
print("Sending status packet done.")
print("Terminated.")
socketio.start_background_task(emitStatus)
Странная вещь, в которой я прошу вас о помощи, заключается в следующем: первый вызов statusQueue.get()
блоков, как и ожидалось, так как изначально очередь пуста Первое сообщение берется из очереди и отправляется через socketio
. Отладочные сообщения на клиенте показывают, что веб-клиент получает это сообщение. Отладочные сообщения на сервере показывают, что сообщение успешно отправлено. Но: как только вызывается следующий statusQueue.get()
, вызов блокируется на неопределенный срок, независимо от того, сколько сообщений помещено в очередь.
Я не уверен, поможет ли это, но некоторая дополнительная информация: socketio
связь совершенно не повреждена. Если клиент отправляет данные, все работает. Кроме того, я могу наблюдать за игрой в пинг-понг как на клиенте, так и на сервере, чтобы поддерживать живые соединения.
Мой вопрос: как правильно реализовать сервер, способный асинхронно отправлять сообщения клиенту?
Посмотрите на https://github.com/jkpubsrc/experiment-python-flask-socketio пример минималистичного кода, показывающего процесс сервера Python-Flask и клиент JavaScript на основе JQuery.
(К вашему сведению: поскольку это сообщения о состоянии, необязательно, чтобы приходило каждое сообщение. Но я очень хотел бы получить хотя бы некоторые сообщения, а не только самое первое сообщение, а затем никакого другого сообщения.)
Спасибо за ваши ответы.