# UDP
UDP uses datagram pipelines. The model is similar to TCP, but the boundary is a complete datagram rather than a byte stream.
## Server
`UdpServer::bind(addr)` creates a socket server builder. `.pipeline(|| ...)` sets the socket-level pipeline factory:
```rust
use rs_netty::{codec::Utf8DatagramCodec, datagram_pipeline, handler, Result, UdpServer};
struct UdpEcho;
#[handler(UdpEcho)]
async fn udp_echo(msg: String) -> Result<String> {
Ok(format!("echo: {msg}"))
}
let server = UdpServer::bind("127.0.0.1:0")
.pipeline(|| {
datagram_pipeline()
.codec(Utf8DatagramCodec)
.handler(UdpEcho)
})
.start()
.await?;
server.shutdown();
server.wait().await?;
# Ok::<(), rs_netty::Error>(())
```
`UdpServerHandle` exposes `local_addr()`, `shutdown()`, and `wait()`.
## Client
`UdpClient::connect(remote_addr)` binds to `"0.0.0.0:0"` by default. Use `.bind(local_addr)` to choose a local address. `UdpClientHandle<W>` provides these methods for the default remote peer:
- `write(msg)`
- `flush()`
- `write_and_flush(msg)`
It also supports explicit peers:
- `write_to(peer_addr, msg)`
- `write_to_and_flush(peer_addr, msg)`
## Socket-Level Pipeline
A UDP server currently creates one socket-level pipeline, not a child pipeline per peer. For every datagram, the runtime creates new `DatagramInfo`, `InboundContext`, `BusinessContext`, `DatagramContext`, and `OutboundContext` values. `peer_addr()` is the sender of the current datagram.
If the application needs per-peer state, store it in the handler yourself:
```rust
use std::{collections::HashMap, net::SocketAddr};
struct PeerState;
struct StatefulUdp {
peers: HashMap<SocketAddr, PeerState>,
}
```
## Configuration
UDP uses `UdpSocketConfig`:
- `read_buffer_capacity`: default 64 KiB; normalized to at least `max_datagram_size`.
- `write_buffer_capacity`: default 8 KiB.
- `max_datagram_size`: default 64 KiB.
- `outbound_queue_size`: default 1024.
Builder methods include:
- `read_buffer_capacity(value)`
- `write_buffer_capacity(value)`
- `max_datagram_size(value)`
- `outbound_queue_size(value)`
UDP currently has no TCP-style `tcp_nodelay`, connection stats, or idle timeout.
## Datagram Write Semantics
`DatagramContext::write(msg)` writes to the current datagram peer. `write_to(peer, msg)` writes to an explicit peer. Both only stage data in the handler-local outbox. `flush` or `*_and_flush` sends pending datagrams through `send_to`.
A UDP flush acknowledgement only means the local `send_to` call completed. It does not mean the peer received the datagram, and UDP still provides no ordering, retransmission, or reliability guarantee.