Skip to content

Instantly share code, notes, and snippets.

@momijiame
Created March 28, 2017 08:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save momijiame/e1e1ee04565a6fcf865a39000a112b94 to your computer and use it in GitHub Desktop.
Save momijiame/e1e1ee04565a6fcf865a39000a112b94 to your computer and use it in GitHub Desktop.
asyncio の低レイヤーな API で書いたエコーサーバ
#!/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