Created
March 28, 2017 08:06
-
-
Save momijiame/e1e1ee04565a6fcf865a39000a112b94 to your computer and use it in GitHub Desktop.
asyncio の低レイヤーな API で書いたエコーサーバ
This file contains hidden or 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 python | |
# -*- coding: utf-8 -*- | |
import asyncio | |
import socket | |
# イベントループに使うオブジェクトを用意する | |
ev_loop = asyncio.get_event_loop() | |
# 接続してきたクライアントとの接続情報を格納する | |
connections = {} | |
def accept_handler(serversocket): | |
"""サーバソケットが読み取り可能になったとき呼ばれるハンドラ""" | |
clientsocket, (client_address, client_port) = serversocket.accept() | |
print('New client: {0}:{1}'.format(client_address, client_port)) | |
connections[clientsocket.fileno()] = (clientsocket, | |
client_address, | |
client_port) | |
# クライアントソケットが読み取り可能になるまで待つ | |
ev_loop.add_reader(clientsocket.fileno(), | |
recv_handler, clientsocket.fileno()) | |
def recv_handler(fileno): | |
"""クライアントソケットが読み取り可能になったとき呼ばれるハンドラ""" | |
def terminate(): | |
del connections[clientsocket.fileno()] | |
clientsocket.close() | |
print('Bye-Bye: {0}:{1}'.format(client_address, client_port)) | |
clientsocket, client_address, client_port = connections[fileno] | |
try: | |
message = clientsocket.recv(1024) | |
except OSError: | |
terminate() | |
return | |
if len(message) == 0: | |
terminate() | |
return | |
print('Recv: {0} to {1}:{2}'.format(message, | |
client_address, | |
client_port)) | |
# 読み取り可能待ちの状態は解除する | |
ev_loop.remove_reader(clientsocket.fileno()) | |
# クライアントソケットが書き込み可能になるまで待つ | |
ev_loop.add_writer(clientsocket.fileno(), send_handler, fileno, message) | |
def send_handler(fileno, message): | |
"""クライアントソケットが書き込み可能になったとき呼ばれるハンドラ""" | |
clientsocket, client_address, client_port = connections[fileno] | |
sent_len = clientsocket.send(message) | |
print('Send: {0} to {1}:{2}'.format(message[:sent_len], | |
client_address, | |
client_port)) | |
# 書き込可能待ちの状態は解除する | |
ev_loop.remove_writer(clientsocket.fileno()) | |
if sent_len == len(message): | |
# 全て送ることができたら、次はまたソケットが読み取れるようになるのを待つ | |
ev_loop.add_reader(clientsocket.fileno(), | |
recv_handler, clientsocket.fileno()) | |
else: | |
# 送り残している内容があったら、再度ソケットが書き込み可能になるまで待つ | |
ev_loop.add_writer(clientsocket.fileno(), | |
send_handler, fileno, message[sent_len:]) | |
def main(): | |
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
# ソケットをノンブロックモードにする | |
serversocket.setblocking(False) | |
serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) | |
host = 'localhost' | |
port = 37564 | |
serversocket.bind((host, port)) | |
serversocket.listen(128) | |
# サーバソケットにクライアントが接続してきたときのハンドラを登録する | |
ev_loop.add_reader(serversocket, accept_handler, serversocket) | |
# イベントループを起動する | |
try: | |
ev_loop.run_forever() | |
finally: | |
# 後始末 | |
ev_loop.close() | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment