Last active
April 20, 2021 21:17
-
-
Save marceloalcocer/15c4bc91ab69f8df465a7eb4acb0db8b to your computer and use it in GitHub Desktop.
TCP echo server implemented using asyncio
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
"""TCP echo server | |
Implemented using asyncio for concurrent client handling | |
""" | |
import asyncio | |
import argparse | |
import logging | |
class EchoServer: | |
address = "localhost" | |
port = 8888 | |
_server = None | |
def __init__(self, address=None, port=None): | |
logging.basicConfig( | |
level=logging.INFO, | |
format="[%(asctime)s] %(levelname)s: %(message)s" | |
) | |
if address is not None: | |
self.address = address | |
if port is not None: | |
self.port = port | |
async def _init_server(self): | |
"""Instantiate server""" | |
self._server = await asyncio.start_server( | |
self._echo, | |
host=self.address, | |
port=self.port, | |
start_serving=False | |
) | |
async def _echo(self, reader, writer): | |
"""Echo connection data""" | |
client = writer.get_extra_info("peername") | |
logging.info(f"{client}: Connected") | |
data = await reader.readline() | |
while data: | |
logging.info(f"{client}: Received: {data}") | |
await asyncio.sleep(1) # Simulate e.g. network latency | |
writer.write(data) | |
await writer.drain() | |
logging.info(f"{client}: Sent: {data}") | |
data = await reader.readline() | |
writer.write_eof() | |
writer.close() | |
await writer.wait_closed() | |
logging.info(f"{client}: Disconnected") | |
async def _listen(self): | |
"""Start listening""" | |
async with self._server: | |
logging.info("Echo server started") | |
logging.info(f"Listening on {self.address}:{self.port}") | |
await self._server.serve_forever() | |
async def __call__(self): | |
"""Async main""" | |
await self._init_server() | |
await self._listen() | |
def up(self): | |
"""Start server""" | |
try: | |
asyncio.run(self()) | |
except KeyboardInterrupt: | |
logging.info("Stopping echo server") | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser( | |
description="A simple TCP echo server" | |
) | |
parser.add_argument( | |
"-a", "--address", | |
nargs="?", | |
default=EchoServer.address, | |
help="Server address" | |
) | |
parser.add_argument( | |
"-p", "--port", | |
nargs="?", | |
type=int, | |
default=EchoServer.port, | |
help="Port to listen on" | |
) | |
args = parser.parse_args() | |
EchoServer(address=args.address, port=args.port).up() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment