Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AnyIO-based UDP PoC #340

Closed
wants to merge 1 commit into from
Closed

AnyIO-based UDP PoC #340

wants to merge 1 commit into from

Conversation

florimondmanca
Copy link
Member

Prompted by #275 (comment)

This demonstrates how we could build an UDPStream interface to support the needs of HTTP/3 support via aioquic.

@jlaine This PoC only provides single-target read/write operations. Will we actually need to send data to arbitrary hosts to implement QUIC+HTTP/3?

@sethmlarson While there would be a clear benefit to using AnyIO in terms of slimming down the burden of maintaining I/O operations for various libraries, I think this PR shows we'd still need our stream and concurrency backend interfaces, if only for the timeout/retry policies.

Example server:

"""Hello world UDP server."""

import anyio


async def main() -> None:
    async with await anyio.create_udp_socket(port=5678) as socket:
        print("Connected")
        async for packet, (host, port) in socket.receive_packets(1024):
            response = b", ".join((b"Hello", packet))
            print(f"Response(data={response!r}, host={host!r}, port={port!r})")
            await socket.send(response, host, port)


anyio.run(main)

Example client:

"""Hello world UDP client."""
import anyio

from httpx.concurrency.anyio import AnyioBackend
from httpx.config import DEFAULT_TIMEOUT_CONFIG


async def main() -> None:
    backend = AnyioBackend()
    stream = await backend.open_udp_stream(
        "127.0.0.1", 5678, timeout=DEFAULT_TIMEOUT_CONFIG
    )
    await stream.write(b"Bob")
    datagram = await stream.read(1024)
    assert datagram.data == b"Hello, Bob", datagram.data
    assert datagram.address == "127.0.0.1", datagram.address
    assert datagram.port == 5678, datagram.port

    await stream.close()


anyio.run(main)

@sethmlarson
Copy link
Contributor

Yep, definitely will need our stream and backend interfaces. And to answer for @jlaine based on my understanding of QUIC we'd need to be able to support sending to multiple different hosts. The return type for datagrams_to_send() is typing.List[typing.Tuple[NetworkAddress, bytes]]

@florimondmanca
Copy link
Member Author

Yes, sounds good. I'm actually going to close this, not expecting us to merge this anyway, but I think it was a useful experiment.

@jlaine
Copy link

jlaine commented Sep 22, 2019

Yep, definitely will need our stream and backend interfaces. And to answer for @jlaine based on my understanding of QUIC we'd need to be able to support sending to multiple different hosts. The return type for datagrams_to_send() is typing.List[typing.Tuple[NetworkAddress, bytes]]

You are correct concerning the return type of datagrams_to_send, but bear in mind this covers both the client and server case, which are not identical. A client may change IP address any number of times as it switches between networks. In the current QUIC/HTTP3 drafts, the only case in which a server is expected to change address is if it announces a PreferredAddress (in the transport parameters which are conveyed during the TLS handshake) and the client switches to it.

@florimondmanca florimondmanca deleted the feat/udp-stream branch October 4, 2019 22:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants