🍣

【Python】asyncio で HTTP/1 クライアントをつくる

2024/07/18に公開

公式マニュアルのサンプルコードをコピペして送るメッセージを修正すれば HTTP/1 クライアントになる

client.py
import asyncio

# https://docs.python.org/ja/3/library/asyncio-stream.html#tcp-echo-client-using-streams

async def tcp_client(host, port, message):
    reader, writer = await asyncio.open_connection(
    host, port)

    print(f'Send: {message!r}')
    writer.write(message.encode())
    await writer.drain()

    data = await reader.read(1024)
    print(f'Received: {data.decode()!r}')

    print('Close the connection')
    writer.close()
    await writer.wait_closed()


host = '127.0.0.1'
port = 8000
message = "GET / HTTP/1.1\r\n\r\n"

asyncio.run(tcp_client(host, port, message))

asyncio.Protocol を継承するクラスの例は次のようになる

client.py
import asyncio

# https://docs.python.org/ja/3.13/library/asyncio-protocol.html#tcp-echo-client

class ClientProtocol(asyncio.Protocol):
    def __init__(self, message, on_con_lost):
        self.message = message
        self.on_con_lost = on_con_lost

    def connection_made(self, transport):
        transport.write(self.message.encode())
        print('Data sent: {!r}'.format(self.message))

    def data_received(self, data):
        print('Data received: {!r}'.format(data.decode()))


    def connection_lost(self, exc):
        print('The server closed the connection')
        self.on_con_lost.set_result(True)

async def main():
    host = '127.0.0.1'
    port = 8000
    message = "GET / HTTP/1.1\r\n\r\n"

    loop = asyncio.get_running_loop()
    on_con_lost = loop.create_future()

    transport, protocol = await loop.create_connection(
        lambda: ClientProtocol(message, on_con_lost),
        host, port)

    try:
        await on_con_lost
    finally:
        transport.close()


asyncio.run(main())

Discussion