如何在TCP服务器中使用Tornado.gen.coroutine?

时间:2015-07-11 05:44:13

标签: python tcp tornado yield

我用Tornado写一个Tcp服务器。 这是代码:

#! /usr/bin/env python
#coding=utf-8

from tornado.tcpserver import TCPServer
from tornado.ioloop import IOLoop
from tornado.gen import *
class TcpConnection(object):
    def __init__(self,stream,address):
        self._stream=stream
        self._address=address
        self._stream.set_close_callback(self.on_close)
        self.send_messages()


    def send_messages(self):
        self.send_message(b'hello \n')
        print("next")
        self.read_message()

        self.send_message(b'world \n')

        self.read_message()


    def read_message(self):
        self._stream.read_until(b'\n',self.handle_message)

    def handle_message(self,data):
        print(data)

    def send_message(self,data):

        self._stream.write(data)

    def on_close(self):
        print("the monitored %d has left",self._address)

class MonitorServer(TCPServer):

    def handle_stream(self,stream,address):
        print("new connection",address,stream)
        conn = TcpConnection(stream,address)

if  __name__=='__main__':
    print('server start .....')
    server=MonitorServer()
    server.listen(20000)
    IOLoop.instance().start()

我面对一些错误assert self._read_callback is None, "Already reading",我想eorror是因为多个命令同时从套接字读取。然后我用tornado.gen.coroutine.here改变函数send_messages是代码:

@gen.coroutine
    def send_messages(self):
        yield self.send_message(b'hello \n')
        response1 = yield self.read_message()
        print(response1)
        yield self.send_message(b'world \n')
        print((yield self.read_message()))

但还有其他一些错误。代码似乎在yield self.send_message(b'hello \n')之后停止,并且以下代码似乎不会执行。 我该怎么办呢?如果你知道任何龙卷风tcpserver(不是HTTP!)代码与tornado.gen.coroutine,请告诉我。我会感激任何链接!

1 个答案:

答案 0 :(得分:3)

send_messages()使用send_message()调用read_message()yield,但这些方法不是协同程序,因此会引发异常。

您没有看到异常的原因是您调用了send_messages()而没有让它出现,因此异常无处可去(垃圾收集器最终应该注意并打印异常,但这可能需要很长时间)。每当你调用一个协程时,你应该使用yield等待它完成,或IOLoop.current().spawn_callback()在"背景"中运行协同程序。 (这告诉Tornado你​​不打算产生协程,所以它会在它发生时立即打印出来)。此外,每当您覆盖一个方法时,您应该阅读文档以查看是否允许协程(当您覆盖TCPServer.handle_stream()时,可以使其成为协程,但__init__()可能不是协程。)

记录异常后,下一步就是修复它。您可以制作send_message()read_message()协同程序(在此过程中删除handle_message()回调),也可以使用tornado.gen.Task()从协程中调用协同式代码。我一般建议到处使用协同程序。