Search code examples
tornado

async with Tornado TCPClient and TCPServer


I am having trouble getting the TCPClient and TCPServer going in Tornado.

I have the following server code:

from tornado import gen
from tornado.ioloop import IOLoop
from tornado.iostream import IOStream, StreamClosedError
from tornado.tcpclient import TCPClient
from tornado.tcpserver import TCPServer
from tornado.platform.asyncio import to_tornado_future, to_asyncio_future


class MyServer(TCPServer):

    async def handle_stream(self, stream, address):
        try:
            while True:
               encoded="***".encode()
               msg= await stream.read_until(encoded)
               print(msg)

        except StreamClosedError:
            print("connection error")

server = MyServer()
server.listen(10000)
IOLoop.current().start()

and the following client code:

from tornado import gen
from tornado.ioloop import IOLoop
from tornado.iostream import IOStream, StreamClosedError
from tornado.tcpclient import TCPClient
from tornado.platform.asyncio import to_tornado_future, to_asyncio_future
tcp_client = TCPClient()


async def client():
    while True:
        try:
            stream = await  tcp_client.connect('localhost', 10000)

            # Set TCP_NODELAY / disable Nagle's Algorithm.
            stream.set_nodelay(True)

            while True:
                msg ="hello ***"
                await  stream.write(msg.encode())
                await gen.sleep(5)

        except StreamClosedError as exc:
            print("error connecting")

loop = IOLoop.current()
loop.spawn_callback(client)
loop.start()

I keep getting a warnings on the server side that handle_stream was never awaited:

/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/tornado-4.4.2-py3.5-macosx-10.6-intel.egg/tornado/netutil.py:272: RuntimeWarning: coroutine 'MyServer.handle_stream' was never awaited
  callback(connection, address)
ERROR:tornado.application:Error in connection callback
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/tornado-4.4.2-py3.5-macosx-10.6-intel.egg/tornado/tcpserver.py", line 276, in _handle_connection
    self.io_loop.add_future(future, lambda f: f.result())
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/tornado-4.4.2-py3.5-macosx-10.6-intel.egg/tornado/ioloop.py", line 593, in add_future

Can someone please tell me what i'm doing wrong and how I can get this working with async and await.

this is related to the following question that Jesse kindly answered:

Tornado TCP Server / Client process communication

I tried to get his code working with async and await however had the same issues.... If I change the above code to use yield and coroutines it works...


Solution

  • I see the problem, will fix here: github.com/tornadoweb/tornado/pull/1906 meanwhile I think handle_stream can't be a native coroutine, at least not in any convenient way.