Tornado 客户端 on_message_callback 没有响应
tornado client on_message_callback is not responding
我正在为服务器和客户端构建一个简单的应用程序,以便在我构建更复杂的应用程序之前提前传递数据。这个问题的目的很简单。在这里,客户端每秒向服务器创建数据,如果从客户端接收到的数据是文本消息,如 "send",服务器也会发回一些数据。我几乎要创建这个类似的应用程序。但是它没有用,所以我花了将近一周的时间来浪费我的周末。
问题是服务器收到请求客户端消息的消息后,服务器好像按照日志发送了数据,但是客户端没有响应。据我了解,我认为调用 cb_receive() 的回调函数应该对此做出响应。
我用下面的简单应用程序创建了这个问题。如果您擅长 asyncio 和 tornado 库,请告诉我。再次感谢!
服务器端
import tornado.ioloop
import tornado.web
import tornado.websocket
import os
from tornado import gen
class EchoWebSocket(tornado.websocket.WebSocketHandler):
def open(self):
self.write_message('hello')
@gen.coroutine
def on_message(self, message):
print(message)
yield self.write_message('notification : ', message)
def on_close(self):
print("A client disconnected!!")
if __name__ == "__main__":
app = tornado.web.Application([(r"/", EchoWebSocket)])
app.listen(os.getenv('PORT', 8344))
tornado.ioloop.IOLoop.instance().start()
客户端
from tornado.ioloop import IOLoop, PeriodicCallback
from tornado import gen
from tornado.websocket import websocket_connect
@gen.coroutine
def cb_receive(msg):
print('msg----------> {}'.format(msg))
class Client(object):
def __init__(self, url, timeout):
self.url = url
self.timeout = timeout
self.ioloop = IOLoop.instance()
self.ws = None
self.connect()
self.ioloop.start()
@gen.coroutine
def connect(self):
print("trying to connect")
try:
self.ws = yield websocket_connect(self.url,on_message_callback=cb_receive)
except Exception as e:
print("connection error")
else:
print("connected")
self.run()
@gen.coroutine
def run(self):
while True:
print('please input')
msg = input()
yield self.ws.write_message(msg)
print('trying to send msg {}'.format(msg))
if __name__ == "__main__":
client = Client("ws://localhost:8344", 5)
请帮帮我!我不仅尝试了上面的这个龙卷风库,还尝试了 websockets 和其他库。但是没用。
为什么会这样?
这是因为 run
方法中的 while
循环比 Tornado 调用 cb_receive
.
方法迭代得更快
解决这个问题的一个肮脏的技巧是在循环结束时休眠一小段时间。这样,IOLoop
变得自由,并且可以 运行 其他协程和回调。
示例:
while True:
# other code ...
yield gen.sleep(0.01)
如果您 运行 您的客户端,您会看到 cb_receive
回调在服务器发送消息时被调用。
但这是一个非常糟糕的解决方案。我刚刚提到它,所以实际问题很明显。现在,我想您知道 cb_recieve
回调未被调用的原因了。
有什么解决办法?
出现此问题的真正原因是 while
循环太快。一个肮脏的解决方案是让循环休眠一段时间。
但这是一个非常低效的解决方案。因为 input()
函数本质上是阻塞的。因此,当 while
循环到达 msg = input()
行时,整个 IOLoop 就挂在那里。这意味着在您输入消息之前,Tornado 不能 运行 任何其他内容。如果服务器在此期间发送更多消息,Tornado 将无法 运行 回调。
通常情况下,非阻塞应用程序在等待某事或某个事件时应该能够做其他事情。例如,如果 Tornado 正在等待您的输入,它应该能够 运行 在您没有提供任何输入的情况下进行其他操作。但事实并非如此,因为 input()
函数正在阻塞。
更好的解决方案是以非阻塞方式接收用户输入。您可以使用 sys.stdin
完成此任务。
示例(修改自 的代码):
import sys
class Client:
...
self.ioloop.add_handler(sys.stdin, self.handle_input, IOLoop.READ)
@gen.coroutine
def handle_input(self, fd, events):
msg = fd.readline()
yield self.ws.write_message(msg)
@gen.coroutine
def run(self):
# the run method would have nothing
# but you can put a print statement
# here, remove everything else
print("please input")
# a small optional modification to the cb_recieve function
@gen.coroutine
def cb_receive(msg):
print('msg----------> {}'.format(msg))
# the following print statement is just there
# to mimic the while loop behaviour
# to print a "please input" message
# to ask user for input because
# sys.stdin in always listening for input
print("please input")
我正在为服务器和客户端构建一个简单的应用程序,以便在我构建更复杂的应用程序之前提前传递数据。这个问题的目的很简单。在这里,客户端每秒向服务器创建数据,如果从客户端接收到的数据是文本消息,如 "send",服务器也会发回一些数据。我几乎要创建这个类似的应用程序。但是它没有用,所以我花了将近一周的时间来浪费我的周末。
问题是服务器收到请求客户端消息的消息后,服务器好像按照日志发送了数据,但是客户端没有响应。据我了解,我认为调用 cb_receive() 的回调函数应该对此做出响应。
我用下面的简单应用程序创建了这个问题。如果您擅长 asyncio 和 tornado 库,请告诉我。再次感谢!
服务器端
import tornado.ioloop
import tornado.web
import tornado.websocket
import os
from tornado import gen
class EchoWebSocket(tornado.websocket.WebSocketHandler):
def open(self):
self.write_message('hello')
@gen.coroutine
def on_message(self, message):
print(message)
yield self.write_message('notification : ', message)
def on_close(self):
print("A client disconnected!!")
if __name__ == "__main__":
app = tornado.web.Application([(r"/", EchoWebSocket)])
app.listen(os.getenv('PORT', 8344))
tornado.ioloop.IOLoop.instance().start()
客户端
from tornado.ioloop import IOLoop, PeriodicCallback
from tornado import gen
from tornado.websocket import websocket_connect
@gen.coroutine
def cb_receive(msg):
print('msg----------> {}'.format(msg))
class Client(object):
def __init__(self, url, timeout):
self.url = url
self.timeout = timeout
self.ioloop = IOLoop.instance()
self.ws = None
self.connect()
self.ioloop.start()
@gen.coroutine
def connect(self):
print("trying to connect")
try:
self.ws = yield websocket_connect(self.url,on_message_callback=cb_receive)
except Exception as e:
print("connection error")
else:
print("connected")
self.run()
@gen.coroutine
def run(self):
while True:
print('please input')
msg = input()
yield self.ws.write_message(msg)
print('trying to send msg {}'.format(msg))
if __name__ == "__main__":
client = Client("ws://localhost:8344", 5)
请帮帮我!我不仅尝试了上面的这个龙卷风库,还尝试了 websockets 和其他库。但是没用。
为什么会这样?
这是因为 run
方法中的 while
循环比 Tornado 调用 cb_receive
.
解决这个问题的一个肮脏的技巧是在循环结束时休眠一小段时间。这样,IOLoop
变得自由,并且可以 运行 其他协程和回调。
示例:
while True:
# other code ...
yield gen.sleep(0.01)
如果您 运行 您的客户端,您会看到 cb_receive
回调在服务器发送消息时被调用。
但这是一个非常糟糕的解决方案。我刚刚提到它,所以实际问题很明显。现在,我想您知道 cb_recieve
回调未被调用的原因了。
有什么解决办法?
出现此问题的真正原因是 while
循环太快。一个肮脏的解决方案是让循环休眠一段时间。
但这是一个非常低效的解决方案。因为 input()
函数本质上是阻塞的。因此,当 while
循环到达 msg = input()
行时,整个 IOLoop 就挂在那里。这意味着在您输入消息之前,Tornado 不能 运行 任何其他内容。如果服务器在此期间发送更多消息,Tornado 将无法 运行 回调。
通常情况下,非阻塞应用程序在等待某事或某个事件时应该能够做其他事情。例如,如果 Tornado 正在等待您的输入,它应该能够 运行 在您没有提供任何输入的情况下进行其他操作。但事实并非如此,因为 input()
函数正在阻塞。
更好的解决方案是以非阻塞方式接收用户输入。您可以使用 sys.stdin
完成此任务。
示例(修改自
import sys
class Client:
...
self.ioloop.add_handler(sys.stdin, self.handle_input, IOLoop.READ)
@gen.coroutine
def handle_input(self, fd, events):
msg = fd.readline()
yield self.ws.write_message(msg)
@gen.coroutine
def run(self):
# the run method would have nothing
# but you can put a print statement
# here, remove everything else
print("please input")
# a small optional modification to the cb_recieve function
@gen.coroutine
def cb_receive(msg):
print('msg----------> {}'.format(msg))
# the following print statement is just there
# to mimic the while loop behaviour
# to print a "please input" message
# to ask user for input because
# sys.stdin in always listening for input
print("please input")