asyncio 서버 작성

매일 공부(ML)·2023년 6월 2일
1

Fluent Python

목록 보기
130/130

제어 흐름

asyncio를 이용한 동시성

asyncio 서버 작성

에코 서버는 TCP 서버의 고전적인 예제로, 먼저 TCP로 구현한 뒤 HTTP로 구현하여 유니코드 문자를 찾아내는 서버를 만들 것이고, unicodedata 모듈을 이용해서 클라이언트가 유니코드 공식 명칭으로 유니코드 문자를 검색할 수 있게 해서, 유니코드 문자를 찾아주는 TCP 문자 검색 서버에 텔넷으로 연결한 세션을 보여준다.

asyncio TCP서버

charfinder.py 모듈이 있고, 동시성을 전혀 사용하지 않으며 charfinder.py는 명령행에서 문자를 검색하기 위해 사용할 수도 있지만 asyncio 서버에 콘텐츠를 제공하기 위해서 설계 되었고, charfinder 모듈은 파이썬에 기본 제공되는 유니코드 데이터베이스의 문자명에 나타나는 단어들을 인덱싱하고, 역인데스를 생성해서 딕셔너리에 저장한다. 역인덱스 항목은 지역의 charfinder_index.pickle파일에 저장된다.

#tcp_charfinder.py:asyncio.start_server()를 사용한 간단한 TCP 서버

import sys
import asyncio

from charfinder import UnicodeNameIndex

CRLF = b'\r\n'
PROMPT = b'?>'

index = UnicodeNameIndex()

@asyncio.coroutine
def handle_queries(reader, writer):
	while True:
    	writer.write(PROMPT) # yield from 을 사용할 수 없다.
        DATA = yield from writer.drain()
        data = yield from reader.readline()
        try:
        	query = data.decode().strip()
        except UnicodeDecodeError:
        	query = '\x00'
        client = writer.get_extra_info('peername')
        print('Received from {}: {!r}'.format(client,query))
        if query:
        	if ord(query[:1]) <32:
            	break
            lines = list(index, find_description_strs(query))
            if lines:
            	writer.writelines(line.encode() + CRLF for line in lines)
            writer.write(index, status(query, len(lines)).encode()+CRLF)
            
            yield from writer.drain()
            print('Sent {} results'.format(len(lines)))
            
            print('Close the client scoket')
            writer.close()

입출력 메서드들 중 일부는 코루틴이므로 yield from으로 구동해야하고, 그 외 일반 함수들은 호출해야한다. 그러나, 버퍼를 플러시해서 실제로 입출력 작업을 수행하는 StreamWriter.drian() 메서더는 Streamreader.readline()과 동일한 코루틴으로 구현되어 있다.

#tcp_charfinder.py: main()함수가 이벤트 루프와 소켓 서버를 생성 및 해체
def main(address='127.0.0.1', port =2323):
	port = int(port)
    loop = asyncio.get_event_loop()
    server_coro = asyncio.start_server(handle_queries, address, port, loop=loop)
    server = loop.run_until_complete(server_coro)
    host = server.sockets[0].getsockname()
    print("Serving on {}. Hit CTRL-C to stop.' format(host))
    try:
    	loop.run_forever()
    except KeyboardInterrupt:
    	pass
        

tcp_charfinder.py 코드는 바로 사용할 수 있는 서버를 제공하는 고수준 asyncio Stream API (https://docs.python.org/3/library/asyncio-stream.html )를 사용하므로, 일반 함 수나 코루틴 형태로 처리 함수만 구현하면 된다. 그리고 Twisted 프레임워크가 제공하는 전 송 및 프로토콜 추상화에서 영감을 얻은 하위 수준의 전송과 프로토콜 API (https://clocs. python.org/3/library/asyncio-stream.html) 도 있다. 저수준 API 를 이용해서 구현한 TCP 에코 서 버 둥에 대한 자세한 정보는 asyncio 의 ‘전송과 프로토콜Transport, and Protocols• 문서
(http://bit.ly/1f6D9i6) 를 참조하라.

profile
성장을 도울 아카이빙 블로그

0개의 댓글