Struct stakker_mio::UdpQueue
source · pub struct UdpQueue {
pub out: VecDeque<Vec<u8>>,
/* private fields */
}
Expand description
Type to aid with managing a connected mio::net::UdpSocket
along with MioPoll
First create the UDP socket and call connect()
on it, add it to
MioPoll
, then pass the resulting MioSource
to
UdpQueue::init
, which allows this struct to manage the
queueing. Your ready handler should call UdpQueue::flush
when
the socket is WRITABLE, and UdpQueue::read
repeatedly until no
more packets are available when the socket is READABLE. For
example:
use stakker_mio::{MioPoll, Ready, UdpQueue, mio::Interest, mio::net::UdpSocket};
use std::net::{IpAddr, SocketAddr};
fn setup_queue(cx: CX![], miopoll: MioPoll, local_ip: IpAddr, remote_addr: SocketAddr)
-> std::io::Result<UdpQueue>
{
// Port 0 means bind to any free emphemeral port
let sock = UdpSocket::bind(SocketAddr::new(local_ip, 0))?;
sock.connect(remote_addr)?;
let sock = miopoll.add(sock, Interest::READABLE | Interest::WRITABLE, 10,
fwd_to!([cx], udp_ready() as (Ready)))?;
let mut queue = UdpQueue::new();
queue.init(sock);
Ok(queue)
}
fn udp_ready(&mut self, cx: CX![], ready: Ready) {
if ready.is_readable() {
let mut tmp = [0; 4096];
loop {
match self.queue.read(&mut tmp) {
Err(e) => return fail!(cx, "UDP recv error: {}", e),
Ok(None) => break,
Ok(Some(slice)) => {
// ... process packet in `slice` ...
}
}
}
}
if ready.is_writable() {
if let Err(e) = self.queue.flush() {
fail!(cx, "UDP send error: {}", e);
}
}
}
Since the socket is assumed to be connected, no peer addresses are required when sending, and no peer addresses are returned on receiving.
Fields§
§out: VecDeque<Vec<u8>>
Output queue. To send, append packets here using
out.push_back()
or the UdpQueue::push
call and then call
UdpQueue::flush
. If the OS buffer is full, then you’ll
see packets building up here. However unlike TCP, UDP has no
mechanism for backpressure, so any buildup should clear
quickly as the OS moves the packets out of its own buffers and
indicates WRITABLE again.
Implementations§
source§impl UdpQueue
impl UdpQueue
sourcepub fn init(&mut self, socket: MioSource<UdpSocket>)
pub fn init(&mut self, socket: MioSource<UdpSocket>)
After adding a socket to the MioPoll instance with
MioPoll::add
, store the MioSource
here to handle the
buffering. UdpQueue
takes care of deregistering the
stream on drop. The caller should probably call
UdpQueue::flush
and UdpQueue::read
soon after this
call.
sourcepub fn deinit(&mut self)
pub fn deinit(&mut self)
Discard the current socket if there is one, deregistering it
from the MioPoll
instance.
sourcepub fn push(&mut self, packet: Vec<u8>)
pub fn push(&mut self, packet: Vec<u8>)
Add a packet to the queue. You must call UdpQueue::flush
soon after.
sourcepub fn read<'a>(&mut self, tmp: &'a mut [u8]) -> Result<Option<&'a [u8]>>
pub fn read<'a>(&mut self, tmp: &'a mut [u8]) -> Result<Option<&'a [u8]>>
Read in a packet, if available. This call is non-blocking.
tmp
is a scratch buffer used for fetching packets, which
should be larger than the largest packet expected. If a
packet is too large, it will be truncated. The largest
possible UDP packet is just under 64KiB. tmp
may be a
reference to an array on the stack, or you might wish to keep
a temporary buffer permanently allocated somewhere if you need
it to be large and avoid the cost of zeroing a buffer
regularly.
On reading a packet, Ok(Some(slice))
is returned, where
slice
is a reference into tmp
. If there is no packet
available, Ok(None)
is returned. This method must be called
repeatedly until it returns Ok(None)
. Only then will mio
be primed to send a new READABLE ready-notification.
Packets are intentionally fetched one at a time, which allows
regulating the input rate if that is required, perhaps in
combination with stakker::idle!
. Since there is no
backpressure in UDP, if you allow too much data to build up in
the OS queue then the OS may drop packets. However dropping
them in the OS queue is more efficient than loading them into
memory and having to drop them there.
sourcepub fn read_to_vec(&mut self, tmp: &mut [u8]) -> Result<Option<Vec<u8>>>
pub fn read_to_vec(&mut self, tmp: &mut [u8]) -> Result<Option<Vec<u8>>>
Read in a packet, if available. Works as for
UdpQueue::read
, except that the data is copied into a new
Vec
.