2016-12-04 107 views
2

我正在嘗試製作一個通常向服務器發送請求並接收響應的應用程序。如果它本來就是這樣的話,我會和HTTP一起去,並稱它爲一筆交易。但是,對服務器的某些請求會對其他客戶端進行更改,因此我希望服務器向所有受影響的客戶端發送一條應該更新的消息。
爲此,我選擇了WebSockets協議和Tornado庫以使用Python進行工作。簡單的消息交換非常簡單,儘管不同步。但是,WebSocket客戶端實際上不是可配置的,我一直在努力讓客戶端監聽傳入的通知,而不會中斷主消息交換。如何使龍捲風websocket客戶端接收服務器通知?

服務器部分由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.WebSocketClientConnectionsource)對象,其具有方法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阻塞,不與龍捲風發揮好。這是這個小玩具演示罰款,但如果你想要做這樣的事情在生產中,你可能會想這樣做環繞sys.stdin一個PipeIOStream和使用stream.read_until('\n')
+0

但是,我們的主要問題?我如何運行常規消息交換並同時接收通知? – Leva7

+0

有了回調函數,你可以擺脫'while/read_message'循環,並在需要時調用'conn.write_message'。使用'input()'做這個工作很棘手,但如果你真正想調用'write_message'的時間在回調中,它就會工作。使用協程,使用'IOLoop.spawn_callback'啓動兩個協程,一個運行讀取循環,另一個執行任何其他您想要執行的操作來生成消息。 –