Python Tornado tcpserver流写入结果

时间:2015-09-01 11:33:23

标签: python sockets stream tornado tcpserver

我有一个简单的龙卷风tcp服务器,有时会写入客户端流。

我想获得stream.write()的结果。无论流是否仍处于活动状态,它始终返回None。

我尝试过使用带有回调和协程的stream.write()。

有没有办法真正获得stream.write()的结果?

这是代码。

fixtures

为了测试客户端流,我使用nc(netcat)。我使用import logging import signal import tornado.httpserver import datetime from tornado import gen logger = logging.getLogger(__name__) class Server(tornado.httpserver.TCPServer): def __init__(self, io_loop=None, ssl_options=None, **kwargs): logger.debug('tcp server started') if not io_loop: io_loop = tornado.ioloop.IOLoop.instance() self.io_loop = io_loop self.streams = [] self.io_loop.add_timeout(datetime.timedelta(seconds=5), self.write_to_all_stream) tornado.httpserver.TCPServer.__init__( self, io_loop=io_loop, ssl_options=ssl_options, **kwargs ) def handle_stream(self, stream, address): logger.debug('New connection from %s' % str(address)) self.streams.append(stream) def on_write_stream(self): logger.debug('written to stream') #@gen.coroutine def write_to_all_stream(self): logger.debug('writing to all streams') for s in self.streams: if s.closed(): logger.debug('Stream is closed!') else: result = s.write('hello', self.on_write_stream) #result = yield s.write('hello') logger.debug('result: %s' % str(result)) def configure_signals(): def bye_handler(signal, frame): logger.info('interrupt signal received, shutting down') io_loop = tornado.ioloop.IOLoop.instance() io_loop.stop() signal.signal(signal.SIGINT, bye_handler) signal.signal(signal.SIGTERM, bye_handler) def configure_logging(): logging.basicConfig( filename=None, level=logging.DEBUG, format='%(asctime)s: %(levelname)7s: [%(name)s]: %(message)s', datefmt='%Y-%m-%d %H:%M:%S', ) if __name__ == '__main__': configure_signals() configure_logging() loop = tornado.ioloop.IOLoop.instance() logger.debug('hello') s = Server().listen(12345, '127.0.0.1') loop.start() logger.debug('bye') / CTRL + C

模拟断开连接
CTRL + Z

操作系统:Ubuntu 14.04

Python:2.7.6

龙卷风版:4.2.0

1 个答案:

答案 0 :(得分:0)

在挖掘了一些东西并测试了各种各样的东西后,我找到了答案。

BaseIOStream.get_fd_error()

哪个州:

  

返回有关基础文件上任何错误的信息。

     

在IOLoop在文件描述符上发出错误信号后调用此方法,并且应该返回一个Exception(例如带有附加信息的socket.error,如果没有这样的信息,则返回None。

http://tornado.readthedocs.org/en/latest/iostream.html#tornado.iostream.BaseIOStream.get_fd_error

以下是上述代码的更新版本。它会检测流错误。

import logging
import signal
import tornado.httpserver
import datetime
import functools


logger = logging.getLogger(__name__)


class Server(tornado.httpserver.TCPServer):
    def __init__(self, io_loop=None, ssl_options=None, **kwargs):

        logger.debug('tcp server started')

        if not io_loop:
            io_loop = tornado.ioloop.IOLoop.instance()

        self.io_loop = io_loop
        self.streams = []

        self.io_loop.add_timeout(datetime.timedelta(seconds=5), self.write_to_all_stream)

        tornado.httpserver.TCPServer.__init__(
            self, io_loop=io_loop, ssl_options=ssl_options, **kwargs
        )        


    def handle_stream(self, stream, address):
        logger.debug('New connection from %s' % str(address))
        self.streams.append(stream)


    def on_write_stream(self, stream):
        status = stream.get_fd_error()

        if status[0]:
            logger.debug('Encountered an error when writing to stream: %s' % str(status[1]))
        else:
            logger.debug('Successfully written to stream')


    def write_to_all_stream(self):
        logger.debug('writing to all streams')

        for s in self.streams:
            s.write('hello', functools.partial(self.on_write_stream, s))


def configure_signals():
    def bye_handler(signal, frame):
        logger.info('interrupt signal received, shutting down')

        io_loop = tornado.ioloop.IOLoop.instance()
        io_loop.stop()

    signal.signal(signal.SIGINT, bye_handler)
    signal.signal(signal.SIGTERM, bye_handler)


def configure_logging():
    logging.basicConfig(
        filename=None,
        level=logging.DEBUG,
        format='%(asctime)s: %(levelname)7s: [%(name)s]: %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S',
    )


if __name__ == '__main__':
    configure_signals()
    configure_logging()

    loop = tornado.ioloop.IOLoop.instance()

    logger.debug('hello')

    s = Server().listen(12345, '127.0.0.1')

    loop.start()

    logger.debug('bye')

<强>更新

对于TCP连接,

stream.write()不是100%可靠。 stream.get_fd_error()在数据被放入操作系统队列时返回(0,'成功')而没有错误,但不保证它到达客户端。为此,您需要在应用级别实施确认系统。

这里有更多细节: https://stackoverflow.com/a/3579609/5069752