Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/rob-blackbourn/jetblack-datagram

A Python 3 asyncio helper library for UDP datagram clients and servers
https://github.com/rob-blackbourn/jetblack-datagram

asyncio datagram python python3 udp udp-client udp-server

Last synced: about 1 month ago
JSON representation

A Python 3 asyncio helper library for UDP datagram clients and servers

Awesome Lists containing this project

README

        

# jetblack-datagram

A Python 3.8+ asyncio helper library for UDP datagram clients and servers.

## Status

This is working, but still under continuous development, so there may be breaking changes.

## Overview

This package provides a simple asyncio API for UDP datagrams, following a
similar pattern to the TCP streams API.

A UDP server is started by calling `start_udp_server` which is
analogous to the
[start_server](https://docs.python.org/3/library/asyncio-stream.html#asyncio.start_server)
function provided by `asyncio`.
This returns a `DatagramServer`, which provides methods for reading (`read`), writing (`sendto`),
and closing (`close` and `wait_closed`). This differs from the TCP variant which provides
a callback when a client connects with a read and write stream. This is because UDP is connection-less
so there is no connect (or disconnect) event. Also the data is sent and received in *packets*,
so there seems to eb no benefit to provide separate read and write stream.

The following creates a server, reads then writes some data.

```python
server = await start_udp_server(('0.0.0.0', 8000))

data, addr = await server.recvfrom()
print(f"Received {data} from {addr}")
server.sendto(b"Hello", addr)

server.close()
await server.wait_closed()
```

A UDP client is started by calling `open_udp_connection` which is analogous
to the
[open_connection](https://docs.python.org/3/library/asyncio-stream.html#asyncio.open_connection)
function provided by the `asyncio` library for TCP, which returns a `DatagramClient`. This provides similar functionality to the
server, however the `addr` is not present when reading or writing, as the socket is bound
to the server address when it is created.

```python
client = await open_udp_connection(('127.0.0.1', 8000))

client.send(b"Hello, World!")
data = await client.recv()
print(f"Received {data}")

client.close()
await client.wait_closed()
```

## Installation

Install using pip.

```bash
pip install jetblack-datagram
```

## Getting Started

To create an echo server:

```python
import asyncio

from jetblack_datagram import start_udp_server

async def main():
server = await start_udp_server(('127.0.0.1', 9999))

count = 0
while count < 5:
count += 1
print("Reading")
data, addr = await server.recvfrom()
print(f"Received {data!r} from {addr}")
print(f"Send {data!r} to {addr}")
server.sendto(data, addr)

print("Closing")
server.close()
print("Waiting for server to close")
await server.wait_closed()
print("Closed")

print("Done")

if __name__ == '__main__':
asyncio.run(main())
```

To create an echo client:

```python
import asyncio

from jetblack_datagram import open_udp_connection

async def main():
client = await open_udp_connection(('127.0.0.1', 9999))

print("Sending data")
client.send(b"Hello, World!")
print("reading data")
data = await client.recv()
print(f"Received {data!r}")

print("closing client")
client.close()
print("waiting for client to close")
await client.wait_closed()

if __name__ == '__main__':
asyncio.run(main())
```

## Usage

The UDP protocol is connection-less, so unlike TCP it makes
no sense to provide a reader for each server connection, or to
provide a callback for connections.

### Common

The following methods are common for both clients and servers.

* close() -> None
* async wait_closed() -> None

### Server

The following methods are specific to the server.

* sendto(data: bytes, addr: Union[Address, str]) -> None
* async recvfrom() -> Tuple[bytes, Address]

### Client

The following methods are specific to the client.

* send(data: bytes) -> None
* async recv() -> bytes

### Helpers

There is a helper to create the server and the client.

For the server:

```python
async def start_udp_server(
addr: Address,
*,
loop: Optional[AbstractEventLoop] = None,
maxreadqueue: int = 0
) -> DatagramServer:
```

For the client:

```python
async def open_udp_connection(
addr: Address,
*,
loop: Optional[AbstractEventLoop] = None,
maxreadqueue: int = 0
) -> DatagramClient:
```