龙卷风客户端 on_message_callback 没有响应 [英] tornado client on_message_callback is not responding

查看:31
本文介绍了龙卷风客户端 on_message_callback 没有响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为服务器和客户端构建一个简单的应用程序,以便在构建更复杂的应用程序之前提前进行数据通信.这个问题的目的很简单.在这里,客户端每秒钟都会向服务器创建数据,如果从客户端收到的数据是像发送"这样的文本消息,服务器也会发回一些数据.我几乎要创建这个类似的应用程序.但它没有用,所以我花了将近一周的时间来浪费我的周末.

I am building a simple application for both a server and a client to communicate data in advance that I build more complex application. Purpose of this problem is very simple. In here, the client creates data over each seconds to the server and server also send back some data if the data received from client is text message like "send". I almost to create this similar application. But It didn't work so that I spent almost a week for this wasting my weekend.

问题是在服务器收到消息后,这意味着向客户端请求消息,服务器似乎按照日志发送了数据,但客户端没有响应.根据我的理解,我认为调用 cb_receive() 的回调函数应该对此做出响应.

The problem is that after the server received the message which means request for message to client, the server seemed to have sent data as per log but the client has no response. As my understanding, I think the callback function called cb_receive() should have responsed for this.

我用下面的简单应用程序创建了这个问题.如果您擅长 asyncio 和 Tornado 库,请告诉我.再次感谢!

I created this problem with simple application below. Please let me know if you are good at asyncio and tornado libraries. Thanks again!

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 和其他库.但是没有用.

Please help me! I tried not only this tornado library above but also websockets and others. But it didn't work.

推荐答案

为什么会这样?

发生这种情况是因为 run 方法中的 while 循环的迭代速度比 Tornado 调用 cb_receive 的速度快.

It's happening because the while loop in the run method is iterating faster than Tornado could call the cb_receive.

解决这个问题的一个肮脏的技巧是在循环结束时睡一小会儿.这样,IOLoop 就变得自由了,可以运行其他协程和回调.

A dirty hack to get around this is to sleep for a small time at the end of the loop. This way, IOLoop becomes free and can run other coroutines and callbacks.

示例:

while True:
    # other code ...
    yield gen.sleep(0.01)

如果您运行您的客户端,您会看到每当服务器发送消息时都会调用 cb_receive 回调.

If you run your client, you'll see the cb_receive callback being called whenever the server sends a message.

但这是一个非常糟糕的解决方案.我刚刚提到它,所以实际问题可以很明显.现在,我想您知道 cb_recieve 回调没有被调用的原因.

But this is a very bad solution. I just mentioned it so the actual problem can be apparent. And now, I think you know the reason why the cb_recieve callback wasn't being called.

解决这个问题的方法是什么?

出现这个问题的真正原因是while 循环太快了.一个肮脏的解决方案是让循环休眠一段时间.

The real reason why this is problem is happening is because while loop is too fast. A dirty solution to that is to put the loop to sleep for a little time.

但这是一个非常低效的解决方案.因为 input() 函数本质上是阻塞的.因此,当 while 循环到达 msg = input() 行时,整个 IOLoop 就挂在那里.这意味着 Tornado 在您输入消息之前无法运行其他任何东西.如果服务器在此期间发送更多消息,Tornado 将无法运行回调.

But that's a very inefficient solution. Because input() function is blocking in nature. So, when the while loop reaches at msg = input() line, the whole IOLoop just hangs there. This means Tornado cannot run anything else until you input a message. If the server sends more messages during that time, Tornado won't be able to run the callback.

通常,非阻塞应用程序在等待某事或某事时应该能够做其他事情.例如,如果 Tornado 正在等待您的输入,它应该能够在您没有提供任何输入的情况下运行其他东西.但事实并非如此,因为 input() 函数正在阻塞.

Normally, a non-blocking application should be able to do other things while it is waiting for something or some event. For example, if Tornado is waiting for your input, it should be able to run other things while you haven't provided it any input. But that's not the case because input() function is blocking.

更好的解决方案是以非阻塞方式接收用户输入.您可以使用 sys.stdin 来完成此任务.

A better solution would be to take user input in a non-blocking manner. You can use sys.stdin for this task.

示例(来自此答案的修改代码):

Example (modified code from this answer):

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")

这篇关于龙卷风客户端 on_message_callback 没有响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆