2015-09-01 37 views
0

我有一個簡單的龍捲風tcp服務器,有時寫入客戶端流。Python Tornado tcpserver流寫入結果

我想要得到stream.write()的結果。無論流是否仍處於活動狀態,它總是返回None。

我已經嘗試使用stream.write()與回調和協程。

有沒有一種方法可以真正得到stream.write()的結果?

這是代碼。

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

對於測試客戶端流,我使用nc(netcat)。我模擬斷開與CTRL + C/CTRL + Z

nc 127.0.0.1 12345 

操作系統:Ubuntu的14.04

的Python:2.7.6

龍捲風版本:4.2.0

回答

0

挖了一下,測試各種事情之後我找到了答案。

BaseIOStream.get_fd_error() 

其中規定:

關於底層文件的任何錯誤返回信息。

的IOLoop對文件描述符信號通知一個錯誤之後,該方法被調用,並且如果沒有這樣的信息可應返回了異常(如socket.error有附加信息,或無。

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

UPD ATE:

對於TCP連接,stream.write()不是100%可靠的。 stream.get_fd_error()返回(0,'成功'),當數據放在操作系統隊列中沒有錯誤,但不能保證它到達客戶端。爲此,您需要在應用程序級別實施確認系統。

更多細節在這裏: https://stackoverflow.com/a/3579609/5069752