--- /dev/null
+TCP echo demo
+=============
+
+This demo shows how to use Tornado's asynchronous TCP client and
+server by implementing `handle_stream` as a coroutine.
+
+To run the server:
+
+```
+$ python server.py
+```
+
+The client will send the message given with the `--message` option
+(which defaults to "ping"), wait for a response, then quit. To run:
+
+```
+$ python client.py --message="your message here"
+```
+
+Alternatively, you can interactively send messages to the echo server
+with a telnet client. For example:
+
+```
+$ telnet localhost 9888
+Trying ::1...
+Connected to localhost.
+Escape character is '^]'.
+ping
+ping
+```
--- /dev/null
+from __future__ import print_function
+from tornado.ioloop import IOLoop
+from tornado import gen
+from tornado.tcpclient import TCPClient
+from tornado.options import options, define
+
+define("host", default="localhost", help="TCP server host")
+define("port", default=9888, help="TCP port to connect to")
+define("message", default="ping", help="Message to send")
+
+
+@gen.coroutine
+def send_message():
+ stream = yield TCPClient().connect(options.host, options.port)
+ yield stream.write((options.message + "\n").encode())
+ print("Sent to server:", options.message)
+ reply = yield stream.read_until(b"\n")
+ print("Response from server:", reply.decode().strip())
+
+
+if __name__ == "__main__":
+ options.parse_command_line()
+ IOLoop.current().run_sync(send_message)
--- /dev/null
+import logging
+from tornado.ioloop import IOLoop
+from tornado import gen
+from tornado.iostream import StreamClosedError
+from tornado.tcpserver import TCPServer
+from tornado.options import options, define
+
+define("port", default=9888, help="TCP port to listen on")
+clients = set()
+logger = logging.getLogger(__name__)
+
+
+class EchoServer(TCPServer):
+ @gen.coroutine
+ def handle_stream(self, stream, address):
+ clients.add(address)
+ while True:
+ try:
+ data = yield stream.read_until(b"\n")
+ logger.info("Received bytes: %s", data)
+ if not data.endswith(b"\n"):
+ data = data + b"\n"
+ yield stream.write(data)
+ except StreamClosedError:
+ clients.remove(address)
+ logger.warning("Lost client at host %s", address[0])
+ break
+ except Exception as e:
+ print(e)
+
+
+if __name__ == "__main__":
+ options.parse_command_line()
+ server = EchoServer()
+ server.listen(options.port)
+ logger.info("Listening on TCP port %d", options.port)
+ IOLoop.current().start()