2016-12-04 2 views
2

Я пытаюсь сделать приложение, которое обычно отправляет запрос на сервер и получает ответ. Если бы это было так, я бы пошел с HTTP и назвал это сделкой. Но некоторые запросы на сервер делают изменения для других клиентов, поэтому я хочу, чтобы сервер отправил всем затронутым клиентам сообщение, которое они должны обновить.
Для этого я выбрал протокол WebSockets и библиотеку Tornado для работы с ним с помощью Python. Простой обмен сообщениями был довольно простым, несмотря на асинхронность. Тем не менее, клиент WebSocket на самом деле не настраивается, и я изо всех сил пытался заставить клиента прослушивать входящие уведомления, не прерывая обмен сообщениями.Как сделать клиент веб-сайта Tornado получать уведомления о сервере?

Серверная часть представлена ​​tornado.websocket.WebSocketHandler, который имеет on_message метод:

from tornado.websocket import WebSocketHandler 

class MyHandler(WebSocketHandler): 
    def on_message(self, message): 
     print('message:', message) 

И я хотел бы что-то подобное, что в клиентской части, которая представлена ​​только функцией tornado.websocket.websocket_connect (source) , Эта функция инициирует объект tornado.websocket.WebSocketClientConnection (source), который имеет метод on_message, но из-за запутанной асинхронной структуры я не смог надлежащим образом отменить его, не нарушая обмена основными сообщениями.

Еще один способ, которым я пытался пойти, был on_message_callback. Это звучало как то, что я мог использовать, но я не мог понять, как использовать его с read_message. Это была моя лучшая попытка:

import tornado.websocket 
import tornado.ioloop 

ioloop = tornado.ioloop.IOLoop.current() 

def clbk(message): 
    print('received', message) 

async def main(): 
    url = 'server_url_here' 
    conn = await tornado.websocket.websocket_connect(url, io_loop = ioloop, on_message_callback=clbk) 
    while True: 
     print(await conn.read_message()) # The execution hangs here 
     st = input() 
     conn.write_message(st) 

ioloop.run_sync(main) 

При этом, как код сервера:

import tornado.ioloop 
import tornado.web 
import tornado.websocket 
import os 


class EchoWebSocket(tornado.websocket.WebSocketHandler): 
    def open(self): 
     self.write_message('hello') 

    def on_message(self, message): 
     self.write_message(message) 
     self.write_message('notification') 

if __name__ == "__main__": 
    app = tornado.web.Application([(r"/", EchoWebSocket)]) 
    app.listen(os.getenv('PORT', 8080)) 
    tornado.ioloop.IOLoop.current().start() 

Я не знаю, что здесь происходит. Я даже иду в правильном направлении?

ответ

1

Есть две проблемы:

  1. Использование on_message_callback или петля на await read_message(), но не оба. Если вы передадите обратный вызов, сообщения будут переданы только этому обратному вызову и не будут сохранены для использования read_message.
  2. input блокирует и не очень хорошо играет с Торнадо. В этой маленькой игрушечной демонстрации все в порядке, но если вы хотите сделать что-то подобное в производстве, вы, вероятно, захотите сделать что-то вроде обертки PipeIOStream около sys.stdin и использовать stream.read_until('\n').
+0

А как насчет основной проблемы? Как я могу запускать регулярный обмен сообщениями и получать уведомления одновременно? – Leva7

+0

С обратными вызовами вы можете просто избавиться от цикла while/read_message и вызвать 'conn.write_message', когда вам нужно. Трудно сделать эту работу с 'input()', но она будет работать, если времена, когда вы действительно хотите вызвать 'write_message', находятся в обратных вызовах. С помощью сопрограмм используйте «IOLoop.spawn_callback» для запуска двух сопрограмм, один из которых выполняет цикл чтения, а другой - все, что вы хотите сделать, чтобы генерировать сообщения. –

 Смежные вопросы

  • Нет связанных вопросов^_^