mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-09 00:00:08 +02:00
docs: more docs for UdpSocket (#2883)
This commit is contained in:
+243
-2
@@ -8,6 +8,102 @@ use std::net::{self, Ipv4Addr, Ipv6Addr, SocketAddr};
|
|||||||
|
|
||||||
cfg_udp! {
|
cfg_udp! {
|
||||||
/// A UDP socket
|
/// A UDP socket
|
||||||
|
///
|
||||||
|
/// UDP is "connectionless", unlike TCP. Meaning, regardless of what address you've bound to, a `UdpSocket`
|
||||||
|
/// is free to communicate with many different remotes. In tokio there are basically two main ways to use `UdpSocket`:
|
||||||
|
/// - one to many: [`bind`](`UdpSocket::bind`) and use [`send_to`](`UdpSocket::send_to`)
|
||||||
|
/// and `[`recv_from`](`UdpSocket::recv_from`) to communicate with many different addresses
|
||||||
|
/// - one to one: [`connect`](`UdpSocket::connect`) and associate with a single address, using [`send`](`UdpSocket::send`)
|
||||||
|
/// and `[`recv`](`UdpSocket::recv`) to communicate only with that remote address
|
||||||
|
///
|
||||||
|
/// `UdpSocket` can also be used concurrently to `send_to` and `recv_from` in different tasks,
|
||||||
|
/// all that's required is that you `Arc<UdpSocket>` and clone a reference for each task.
|
||||||
|
///
|
||||||
|
/// # Streams
|
||||||
|
///
|
||||||
|
/// If you need to listen over UDP and produce a [`Stream`](`crate::stream::Stream`), you can look
|
||||||
|
/// at [`UdpFramed`].
|
||||||
|
///
|
||||||
|
/// [`UdpFramed`]: https://docs.rs/tokio-util/latest/tokio_util/udp/struct.UdpFramed.html
|
||||||
|
///
|
||||||
|
/// # Example: one to many (bind)
|
||||||
|
///
|
||||||
|
/// Using `bind` we can create a simple echo server that sends and recv's with many different clients:
|
||||||
|
/// ```no_run
|
||||||
|
/// use tokio::net::UdpSocket;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() -> io::Result<()> {
|
||||||
|
/// let sock = UdpSocket::bind("0.0.0.0:8080").await?;
|
||||||
|
/// let mut buf = [0; 1024];
|
||||||
|
/// loop {
|
||||||
|
/// let (len, addr) = sock.recv_from(&mut buf).await?;
|
||||||
|
/// println!("{:?} bytes received from {:?}", len, addr);
|
||||||
|
///
|
||||||
|
/// let len = sock.send_to(&buf[..len], addr).await?;
|
||||||
|
/// println!("{:?} bytes sent", len);
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example: one to one (connect)
|
||||||
|
///
|
||||||
|
/// Or using `connect` we can echo with a single remote address using `send` and `recv`:
|
||||||
|
/// ```no_run
|
||||||
|
/// use tokio::net::UdpSocket;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() -> io::Result<()> {
|
||||||
|
/// let sock = UdpSocket::bind("0.0.0.0:8080").await?;
|
||||||
|
///
|
||||||
|
/// let remote_addr = "127.0.0.1:59611";
|
||||||
|
/// sock.connect(remote_addr).await?;
|
||||||
|
/// let mut buf = [0; 1024];
|
||||||
|
/// loop {
|
||||||
|
/// let len = sock.recv(&mut buf).await?;
|
||||||
|
/// println!("{:?} bytes received from {:?}", len, remote_addr);
|
||||||
|
///
|
||||||
|
/// let len = sock.send(&buf[..len]).await?;
|
||||||
|
/// println!("{:?} bytes sent", len);
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example: Sending/Receiving concurrently
|
||||||
|
///
|
||||||
|
/// Because `send_to` and `recv_from` take `&self`. It's perfectly alright to `Arc<UdpSocket>`
|
||||||
|
/// and share the references to multiple tasks, in order to send/receive concurrently. Here is
|
||||||
|
/// a similar "echo" example but that supports concurrent sending/receiving:
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use tokio::{net::UdpSocket, sync::mpsc};
|
||||||
|
/// use std::{io, net::SocketAddr, sync::Arc};
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() -> io::Result<()> {
|
||||||
|
/// let sock = UdpSocket::bind("0.0.0.0:8080".parse::<SocketAddr>().unwrap()).await?;
|
||||||
|
/// let r = Arc::new(sock);
|
||||||
|
/// let s = r.clone();
|
||||||
|
/// let (tx, mut rx) = mpsc::channel::<(Vec<u8>, SocketAddr)>(1_000);
|
||||||
|
///
|
||||||
|
/// tokio::spawn(async move {
|
||||||
|
/// while let Some((bytes, addr)) = rx.recv().await {
|
||||||
|
/// let len = s.send_to(&bytes, &addr).await.unwrap();
|
||||||
|
/// println!("{:?} bytes sent", len);
|
||||||
|
/// }
|
||||||
|
/// });
|
||||||
|
///
|
||||||
|
/// let mut buf = [0; 1024];
|
||||||
|
/// loop {
|
||||||
|
/// let (len, addr) = r.recv_from(&mut buf).await?;
|
||||||
|
/// println!("{:?} bytes received from {:?}", len, addr);
|
||||||
|
/// tx.send((buf[..len].to_vec(), addr)).await.unwrap();
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
pub struct UdpSocket {
|
pub struct UdpSocket {
|
||||||
io: PollEvented<mio::net::UdpSocket>,
|
io: PollEvented<mio::net::UdpSocket>,
|
||||||
}
|
}
|
||||||
@@ -16,6 +112,21 @@ cfg_udp! {
|
|||||||
impl UdpSocket {
|
impl UdpSocket {
|
||||||
/// This function will create a new UDP socket and attempt to bind it to
|
/// This function will create a new UDP socket and attempt to bind it to
|
||||||
/// the `addr` provided.
|
/// the `addr` provided.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use tokio::net::UdpSocket;
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() -> io::Result<()> {
|
||||||
|
/// let sock = UdpSocket::bind("0.0.0.0:8080").await?;
|
||||||
|
/// // use `sock`
|
||||||
|
/// # let _ = sock;
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub async fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
|
pub async fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
|
||||||
let addrs = to_socket_addrs(addr).await?;
|
let addrs = to_socket_addrs(addr).await?;
|
||||||
let mut last_err = None;
|
let mut last_err = None;
|
||||||
@@ -62,12 +173,44 @@ impl UdpSocket {
|
|||||||
/// The runtime is usually set implicitly when this function is called
|
/// The runtime is usually set implicitly when this function is called
|
||||||
/// from a future driven by a tokio runtime, otherwise runtime can be set
|
/// from a future driven by a tokio runtime, otherwise runtime can be set
|
||||||
/// explicitly with [`Runtime::enter`](crate::runtime::Runtime::enter) function.
|
/// explicitly with [`Runtime::enter`](crate::runtime::Runtime::enter) function.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use tokio::net::UdpSocket;
|
||||||
|
/// # use std::{io, net::SocketAddr};
|
||||||
|
///
|
||||||
|
/// # #[tokio::main]
|
||||||
|
/// # async fn main() -> io::Result<()> {
|
||||||
|
/// let addr = "0.0.0.0:8080".parse::<SocketAddr>().unwrap();
|
||||||
|
/// let std_sock = std::net::UdpSocket::bind(addr)?;
|
||||||
|
/// let sock = UdpSocket::from_std(std_sock)?;
|
||||||
|
/// // use `sock`
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub fn from_std(socket: net::UdpSocket) -> io::Result<UdpSocket> {
|
pub fn from_std(socket: net::UdpSocket) -> io::Result<UdpSocket> {
|
||||||
let io = mio::net::UdpSocket::from_std(socket);
|
let io = mio::net::UdpSocket::from_std(socket);
|
||||||
UdpSocket::new(io)
|
UdpSocket::new(io)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the local address that this socket is bound to.
|
/// Returns the local address that this socket is bound to.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use tokio::net::UdpSocket;
|
||||||
|
/// # use std::{io, net::SocketAddr};
|
||||||
|
///
|
||||||
|
/// # #[tokio::main]
|
||||||
|
/// # async fn main() -> io::Result<()> {
|
||||||
|
/// let addr = "0.0.0.0:8080".parse::<SocketAddr>().unwrap();
|
||||||
|
/// let sock = UdpSocket::bind(addr).await?;
|
||||||
|
/// // the address the socket is bound to
|
||||||
|
/// let local_addr = sock.local_addr()?;
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub fn local_addr(&self) -> io::Result<SocketAddr> {
|
pub fn local_addr(&self) -> io::Result<SocketAddr> {
|
||||||
self.io.get_ref().local_addr()
|
self.io.get_ref().local_addr()
|
||||||
}
|
}
|
||||||
@@ -75,6 +218,27 @@ impl UdpSocket {
|
|||||||
/// Connects the UDP socket setting the default destination for send() and
|
/// Connects the UDP socket setting the default destination for send() and
|
||||||
/// limiting packets that are read via recv from the address specified in
|
/// limiting packets that are read via recv from the address specified in
|
||||||
/// `addr`.
|
/// `addr`.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use tokio::net::UdpSocket;
|
||||||
|
/// # use std::{io, net::SocketAddr};
|
||||||
|
///
|
||||||
|
/// # #[tokio::main]
|
||||||
|
/// # async fn main() -> io::Result<()> {
|
||||||
|
/// let sock = UdpSocket::bind("0.0.0.0:8080".parse::<SocketAddr>().unwrap()).await?;
|
||||||
|
///
|
||||||
|
/// let remote_addr = "127.0.0.1:59600".parse::<SocketAddr>().unwrap();
|
||||||
|
/// sock.connect(remote_addr).await?;
|
||||||
|
/// let mut buf = [0u8; 32];
|
||||||
|
/// // recv from remote_addr
|
||||||
|
/// let len = sock.recv(&mut buf).await?;
|
||||||
|
/// // send to remote_addr
|
||||||
|
/// let _len = sock.send(&buf[..len]).await?;
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub async fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
|
pub async fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
|
||||||
let addrs = to_socket_addrs(addr).await?;
|
let addrs = to_socket_addrs(addr).await?;
|
||||||
let mut last_err = None;
|
let mut last_err = None;
|
||||||
@@ -144,6 +308,22 @@ impl UdpSocket {
|
|||||||
///
|
///
|
||||||
/// The future will resolve to an error if the IP version of the socket does
|
/// The future will resolve to an error if the IP version of the socket does
|
||||||
/// not match that of `target`.
|
/// not match that of `target`.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use tokio::net::UdpSocket;
|
||||||
|
/// # use std::{io, net::SocketAddr};
|
||||||
|
///
|
||||||
|
/// # #[tokio::main]
|
||||||
|
/// # async fn main() -> io::Result<()> {
|
||||||
|
/// let sock = UdpSocket::bind("0.0.0.0:8080".parse::<SocketAddr>().unwrap()).await?;
|
||||||
|
/// let buf = b"hello world";
|
||||||
|
/// let remote_addr = "127.0.0.1:58000".parse::<SocketAddr>().unwrap();
|
||||||
|
/// let _len = sock.send_to(&buf[..], remote_addr).await?;
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub async fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], target: A) -> io::Result<usize> {
|
pub async fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], target: A) -> io::Result<usize> {
|
||||||
let mut addrs = to_socket_addrs(target).await?;
|
let mut addrs = to_socket_addrs(target).await?;
|
||||||
|
|
||||||
@@ -156,16 +336,33 @@ impl UdpSocket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to send data on the socket to the given address.
|
/// Try to send data on the socket to the given address, but if the send is blocked
|
||||||
|
/// this will return right away.
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// If successfull, the future resolves to the number of bytes sent.
|
/// If successfull, returns the number of bytes sent
|
||||||
///
|
///
|
||||||
/// Users should ensure that when the remote cannot receive, the
|
/// Users should ensure that when the remote cannot receive, the
|
||||||
/// [`ErrorKind::WouldBlock`] is properly handled. An error can also occur
|
/// [`ErrorKind::WouldBlock`] is properly handled. An error can also occur
|
||||||
/// if the IP version of the socket does not match that of `target`.
|
/// if the IP version of the socket does not match that of `target`.
|
||||||
///
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use tokio::net::UdpSocket;
|
||||||
|
/// # use std::{io, net::SocketAddr};
|
||||||
|
///
|
||||||
|
/// # #[tokio::main]
|
||||||
|
/// # async fn main() -> io::Result<()> {
|
||||||
|
/// let sock = UdpSocket::bind("0.0.0.0:8080".parse::<SocketAddr>().unwrap()).await?;
|
||||||
|
/// let buf = b"hello world";
|
||||||
|
/// let remote_addr = "127.0.0.1:58000".parse::<SocketAddr>().unwrap();
|
||||||
|
/// let _len = sock.try_send_to(&buf[..], remote_addr)?;
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
/// [`ErrorKind::WouldBlock`]: std::io::ErrorKind::WouldBlock
|
/// [`ErrorKind::WouldBlock`]: std::io::ErrorKind::WouldBlock
|
||||||
pub fn try_send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
|
pub fn try_send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
|
||||||
self.io.get_ref().send_to(buf, target)
|
self.io.get_ref().send_to(buf, target)
|
||||||
@@ -183,6 +380,22 @@ impl UdpSocket {
|
|||||||
/// The function must be called with valid byte array `buf` of sufficient size
|
/// The function must be called with valid byte array `buf` of sufficient size
|
||||||
/// to hold the message bytes. If a message is too long to fit in the supplied
|
/// to hold the message bytes. If a message is too long to fit in the supplied
|
||||||
/// buffer, excess bytes may be discarded.
|
/// buffer, excess bytes may be discarded.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use tokio::net::UdpSocket;
|
||||||
|
/// # use std::{io, net::SocketAddr};
|
||||||
|
///
|
||||||
|
/// # #[tokio::main]
|
||||||
|
/// # async fn main() -> io::Result<()> {
|
||||||
|
/// let sock = UdpSocket::bind("0.0.0.0:8080".parse::<SocketAddr>().unwrap()).await?;
|
||||||
|
/// let mut buf = [0u8; 32];
|
||||||
|
/// let (len, addr) = sock.recv_from(&mut buf).await?;
|
||||||
|
/// println!("received {:?} bytes from {:?}", len, addr);
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
||||||
self.io
|
self.io
|
||||||
.async_io(mio::Interest::READABLE, |sock| sock.recv_from(buf))
|
.async_io(mio::Interest::READABLE, |sock| sock.recv_from(buf))
|
||||||
@@ -273,6 +486,20 @@ impl UdpSocket {
|
|||||||
/// For more information about this option, see [`set_ttl`].
|
/// For more information about this option, see [`set_ttl`].
|
||||||
///
|
///
|
||||||
/// [`set_ttl`]: method@Self::set_ttl
|
/// [`set_ttl`]: method@Self::set_ttl
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use tokio::net::UdpSocket;
|
||||||
|
/// # use std::io;
|
||||||
|
///
|
||||||
|
/// # async fn dox() -> io::Result<()> {
|
||||||
|
/// let sock = UdpSocket::bind("127.0.0.1:8080").await?;
|
||||||
|
///
|
||||||
|
/// println!("{:?}", sock.ttl()?);
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub fn ttl(&self) -> io::Result<u32> {
|
pub fn ttl(&self) -> io::Result<u32> {
|
||||||
self.io.get_ref().ttl()
|
self.io.get_ref().ttl()
|
||||||
}
|
}
|
||||||
@@ -281,6 +508,20 @@ impl UdpSocket {
|
|||||||
///
|
///
|
||||||
/// This value sets the time-to-live field that is used in every packet sent
|
/// This value sets the time-to-live field that is used in every packet sent
|
||||||
/// from this socket.
|
/// from this socket.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use tokio::net::UdpSocket;
|
||||||
|
/// # use std::io;
|
||||||
|
///
|
||||||
|
/// # async fn dox() -> io::Result<()> {
|
||||||
|
/// let sock = UdpSocket::bind("127.0.0.1:8080").await?;
|
||||||
|
/// sock.set_ttl(60)?;
|
||||||
|
///
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
|
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
|
||||||
self.io.get_ref().set_ttl(ttl)
|
self.io.get_ref().set_ttl(ttl)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user