How to set timeout for tornado IOStream?
I've tried construct IOStream by:
sock = socket.socket()
sock.settimeout(5)
self.stream = tornado.iostream.IOStream(sock)
But when I call stream.read_bytes()
, it still keep waiting forever.
You cannot use socket.settimeout()
, because it is designed for blocking IO and Tornado provides non-blocking IO.
Tornado is highly oriented on Web and HTTP IO and it does not allow to do low-level network programming without extreme pain (sources of IOStream
are terrifying).
The best way to set a timeout on a socket is to use select.select()
, select.poll()
, etc, but it's a pain to integrate such approach with Tornado.
I've managed to perform reads with timeouts using combination of gen.with_timeout
and a dirty hack for clearing stream's state.
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)
Good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With