Pythonでasyncioを用いたTCP/UDPサーバーの実装

この記事では、Pythonの非同期I/Oライブラリである`asyncio`を用いてTCPおよびUDPサーバーを作成する方法について詳しく解説します。具体的なコード例とその解説、さらに応用例を2つ含めています。

目次

asyncioとは?

`asyncio`はPython 3.3以降で使用できる標準ライブラリであり、非同期I/Oを簡単に実装できる機能を提供しています。このライブラリを用いると、多くの接続を効率良く処理するサーバーを作成できます。

TCPサーバーの基本構造

サンプルコード

import asyncio

async def handle_client(reader, writer):
    # クライアントからのデータを読む
    data = await reader.read(100)
    message = data.decode()
    
    # クライアントのアドレスを取得
    addr = writer.get_extra_info('peername')
    
    print(f"Received {message} from {addr}")

    # クライアントにデータを送る
    writer.write(data)
    await writer.drain()
    
    writer.close()

async def main():
    server = await asyncio.start_server(handle_client, '127.0.0.1', 8888)
    
    async with server:
        await server.serve_forever()

asyncio.run(main())

コードの詳細解説

– `handle_client`: クライアントからの接続を処理するコルーチン関数です。`reader`と`writer`の二つの引数を受け取ります。
– `reader.read(100)`: クライアントから100バイトまでのデータを非同期で読み込みます。
– `writer.write(data)`: クライアントにデータを非同期で送信します。

補足事項

TCPサーバーの設計では、非同期I/Oを効果的に用いることで多数のクライアントからの接続に対応可能です。`asyncio`を使用することで、このような処理が非常に簡単に実装できます。

UDPサーバーの基本構造

サンプルコード

import asyncio

async def handle_datagram(data, addr):
    print(f"Received {data.decode()} from {addr}")

async def main():
    transport, protocol = await asyncio.loop.create_datagram_endpoint(
        lambda: asyncio.DatagramProtocol(handle_datagram),
        local_addr=('127.0.0.1', 8888))
    
    await asyncio.sleep(3600)

asyncio.run(main())

コードの詳細解説

– `handle_datagram`: UDPパケットを処理するためのコルーチン関数です。
– `create_datagram_endpoint`: UDPサーバーを起動します。

応用例

複数のポートでサーバーを起動

async def main():
    server1 = await asyncio.start_server(handle_client, '127.0.0.1', 8888)
    server2 = await asyncio.start_server(handle_client, '127.0.0.1', 9999)
    
    async with server1, server2:
        await asyncio.gather(server1.serve_forever(), server2.serve_forever())

データベースとの連携

import sqlite3

async def handle_client(reader, writer):
    data = await reader.read(100)
    message = data.decode()
    conn = sqlite3.connect('example.db')
    c = conn.cursor()
    
    # データベースからデータを取得
    c.execute(f"SELECT * FROM table WHERE column='{message}'")
    result = c.fetchone()
    
    writer.write(result)
    await writer.drain()
    
    writer.close()

まとめ

この記事では、Pythonの`asyncio`を用いて、非同期処理でTCP/UDPサーバーを作成する基本的な方法を解説しました。非同期I/Oを活用することで、効率的に多数のクライアント接続を処理できます。応用例として、複数のポートでのサーバー起動やデータベースとの連携も紹介しました。

コメント

コメントする

目次