socket.settimeout()
はIOをブロックするように設計されており、TornadoはノンブロッキングIOを提供するため、使用できません。
Tornadoは、WebとHTTP IOに高度に対応しており、極端な痛み(IOStream
のソースは恐ろしい)なしに低レベルのネットワークプログラミングを行うことはできません。
ソケットにタイムアウトを設定する最も良い方法は、select.select()
,select.poll()
などを使用することですが、このようなアプローチをTornadoと統合するのは苦労です。
私は、gen.with_timeout
の組み合わせとストリームの状態をクリアするための汚れたハックを使用して、タイムアウトで読み込みを実行することができました。
from tornado import gen
from tornado.ioloop import IOLoop
from tornado.tcpclient import TCPClient
timeout = 5
io_loop = IOLoop.current()
factory = TCPClient(io_loop=io_loop)
@gen.coroutine
def run():
stream = yield factory.connect('127.0.0.1', 1234)
try:
future = stream.read_bytes(128)
data = yield gen.with_timeout(
timeout=io_loop.time() + timeout,
future=future,
io_loop=io_loop,
)
except gen.TimeoutError:
# A dirty hack to cancel reading and to clear state of the stream, so
# stream will be available for reading in future
io_loop.remove_handler(stream.socket)
state = (stream._state & ~io_loop.READ)
stream._state = None
stream._read_callback = None
stream._read_future = None
stream._add_io_state(state)
幸運!