Как асинхронно отправлять данные с помощью socketio в веб-клиент? - PullRequest
0 голосов
/ 26 августа 2018

Следующая ситуация:

  • Веб-клиент: использование 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.

(К вашему сведению: поскольку это сообщения о состоянии, необязательно, чтобы приходило каждое сообщение. Но я очень хотел бы получить хотя бы некоторые сообщения, а не только самое первое сообщение, а затем никакого другого сообщения.)

Спасибо за ваши ответы.

1 Ответ

0 голосов
/ 02 сентября 2018

Я оставил два решения, чтобы код работал как запросы на извлечение.

По сути, ответ таков: вы выбираете одну технологию и придерживаетесь ее:

  • Идет async_mode=threading?Отлично, используйте stdlib Queue.Не импортируйте Eventlet, если вам не нужно.
  • Going async_mode=eventlet?Также отлично, используйте Eventlet Queue и не забывайте, что stdlib time.sleep или socket IO заблокирует все остальное, исправьте с помощью eventlet.monkey_patch()
  • Если вы должны использовать и eventlet, и многопоточность, лучший подходчтобы позволить им жить в отдельных процессах ОС и общаться через локальный сокет.Это дополнительная работа, но она очень надежна, и вы знаете, как она работает и почему она не сломается.

Обладая хорошими знаниями как Eventlet, так и собственных потоков, вы можете тщательно смешать их в рабочий код.По состоянию на 2018-09, микширование не работает дружественным и понятным образом, как вы уже обнаружили.Сожалею.Патчи приветствуются.

...