我有一个简单的龙卷风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
答案 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,'成功')而没有错误,但不保证它到达客户端。为此,您需要在应用级别实施确认系统。