입문할 때 간단한 채팅 서버 다들 한번씩 짜셨죠?
아마도 이후로는 쓸 일 없는 select 이용해서 짜셨죠?
이제는 입문용 채팅 서버도 select를 버릴 때가 왔습니다.
대세는 asyncio 입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | import socket import asyncio HOST = '' PORT = 9999 ADDR = (HOST, PORT) class Server: def __init__(self, loop, addr): self.loop = loop self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setblocking(False) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) self.sock.bind(addr) self.sock.listen(5) self.clients = [] asyncio.Task(self.serve()) def broadcast(self, msg): [client.send(msg) for client in self.clients] def remove(self, client): self.clients.remove(client) msg = '########## GUEST {} OUT ##########\n'.format(client.name) self.broadcast(msg) async def serve(self): while True: conn, addr = await self.loop.sock_accept(self.sock) conn.setblocking(False) name = '[' + addr[0] + ']' client = Client(self, conn, name) self.clients.append(client) msg = '########## GUEST {} IN ##########\n'.format(client.name) self.broadcast(msg) class Client: def __init__(self, server, sock, name): self.server = server self.loop = server.loop self.name = name self.sock = sock asyncio.Task(self.handler()) def send(self, msg): return self.loop.sock_sendall(self.sock, msg.encode()) async def handler(self): try: await self.converse() except IOError: pass finally: self.server.remove(self) async def converse(self): while True: buf = await self.loop.sock_recv(self.sock, 1024) if buf == b'': break msg = '{} : {}'.format(self.name, buf.decode()) self.server.broadcast(msg) def runServer(addr): loop = asyncio.get_event_loop() Server(loop, addr) loop.run_forever() if __name__ == '__main__': runServer(ADDR) | cs |
파이썬은 코드가 참 이뻐.. 가독성 갑