pub struct UdpSocket { /* 私有字段 */ }展开描述
一个 UDP 套接字。
UDP 与 TCP 不同,是“无连接”的。这意味着,无论你绑定到什么地址,UdpSocket 都可以自由地与许多不同的远程端通信。在 Tokio 中,基本上有两种主要的使用 UdpSocket 的方式:
- one to many:
bindand usesend_toandrecv_fromto communicate with many different addresses - one to one:
connectand associate with a single address, usingsendandrecvto communicate only with that remote address
本类型不提供 split 方法,因为可以通过将套接字包装在 Arc 中来实现此功能。请注意,你不需要 Mutex 来共享 UdpSocket——一个 Arc<UdpSocket> 就足够了。这是因为所有方法都接受 &self 而非 &mut self。一旦将其包装在 Arc 中,你就可以对 Arc<UdpSocket> 调用 .clone() 来获得多个共享句柄以访问同一套接字。此类用法的示例可在下方找到。
§Streams
如果你需要通过 UDP 进行监听并产生一个 Stream,可以参考 UdpFramed。
§Example: one to many (bind)
使用 bind,我们可以创建一个简单的 echo 服务器,它与许多不同的客户端之间相互收发数据:
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)
或者使用 connect,我们可以使用 send 和 recv 与单个远程地址进行 echo:
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: Splitting with Arc
由于 send_to 和 recv_from 接受 &self,因此完全可以使用 Arc<UdpSocket> 并将其引用共享给多个任务。下面是一个类似的 “echo” 示例,它支持并发的发送/接收:
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();
}
}实现§
源代码§impl UdpSocket
impl UdpSocket
源代码pub async fn bind<A: ToSocketAddrs>(addr: A) -> Result<UdpSocket>
pub async fn bind<A: ToSocketAddrs>(addr: A) -> Result<UdpSocket>
此函数将创建一个新的 UDP 套接字,并尝试将其绑定到所提供的 addr。
使用端口号 0 绑定将请求操作系统为此监听器分配一个端口。所分配的端口可以通过 local_addr 方法查询。
§示例
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`
Ok(())
}源代码pub fn from_std(socket: UdpSocket) -> Result<UdpSocket>
pub fn from_std(socket: UdpSocket) -> Result<UdpSocket>
从先前已绑定的 std::net::UdpSocket 创建一个新的 UdpSocket。
此函数旨在将标准库的 UDP 套接字包装为其 Tokio 等价物。
这可与 socket2 的 Socket 接口配合使用,以便在套接字被移交之前对其进行配置,例如设置 reuse_address 等选项或绑定到多个地址。
§注意
调用者负责确保套接字处于非阻塞模式。否则,对套接字的所有 I/O 操作都会阻塞线程,从而导致意外行为。可以使用 set_nonblocking 设置非阻塞模式。
在阻塞模式下传入监听器始终是错误的,这种情况下行为将来可能会发生变化。例如,可能会发生 panic。
§恐慌
如果未设置线程本地运行时,此函数会发生 panic。
当从由 tokio 运行时驱动的 future 中调用此函数时,运行时通常是隐式设置的;否则可以通过 Runtime::enter 函数显式设置运行时。
§示例
use tokio::net::UdpSocket;
let addr = "0.0.0.0:8080".parse::<SocketAddr>().unwrap();
let std_sock = std::net::UdpSocket::bind(addr)?;
std_sock.set_nonblocking(true)?;
let sock = UdpSocket::from_std(std_sock)?;
// use `sock`源代码pub fn into_std(self) -> Result<UdpSocket>
pub fn into_std(self) -> Result<UdpSocket>
将一个 tokio::net::UdpSocket 转换为 std::net::UdpSocket。
返回的 std::net::UdpSocket 将 nonblocking 模式设置为 true。如需更改阻塞模式,请使用 set_nonblocking。
§示例
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let tokio_socket = tokio::net::UdpSocket::bind("127.0.0.1:0").await?;
let std_socket = tokio_socket.into_std()?;
std_socket.set_nonblocking(false)?;
Ok(())
}源代码pub fn local_addr(&self) -> Result<SocketAddr>
pub fn local_addr(&self) -> Result<SocketAddr>
返回此套接字绑定的本地地址。
§示例
use tokio::net::UdpSocket;
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()?;源代码pub fn peer_addr(&self) -> Result<SocketAddr>
pub fn peer_addr(&self) -> Result<SocketAddr>
返回此套接字所连接到的远程对等方的套接字地址。
§示例
use tokio::net::UdpSocket;
let addr = "0.0.0.0:8080".parse::<SocketAddr>().unwrap();
let peer = "127.0.0.1:11100".parse::<SocketAddr>().unwrap();
let sock = UdpSocket::bind(addr).await?;
sock.connect(peer).await?;
assert_eq!(peer, sock.peer_addr()?);源代码pub async fn connect<A: ToSocketAddrs>(&self, addr: A) -> Result<()>
pub async fn connect<A: ToSocketAddrs>(&self, addr: A) -> Result<()>
连接此 UDP 套接字,为 send() 设置默认目标地址,并限制通过 recv 只能从 addr 指定的地址读取数据包。
§示例
use tokio::net::UdpSocket;
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?;源代码pub async fn ready(&self, interest: Interest) -> Result<Ready>
pub async fn ready(&self, interest: Interest) -> Result<Ready>
等待任何所请求的就绪状态。
此函数通常与 try_recv() 或 try_send() 配对使用。它可用于在单个任务上同时对同一套接字进行 recv / send,而无需拆分套接字。
该函数可能在套接字尚未就绪时完成。这是一种误报,尝试进行操作将返回 io::ErrorKind::WouldBlock。该函数也可能返回空的 Ready 集合,因此应始终检查返回值,如果请求的状态未设置,可能需要再次等待。
§取消安全性
此方法可安全取消。一旦就绪事件发生,该方法将继续立即返回,直到通过尝试读取或写入而消费该就绪事件(失败时返回 WouldBlock 或 Poll::Pending)。
§示例
在同一任务上同时对套接字进行接收和发送,而无需拆分。
use tokio::io::{self, Interest};
use tokio::net::UdpSocket;
#[tokio::main]
async fn main() -> io::Result<()> {
let socket = UdpSocket::bind("127.0.0.1:8080").await?;
socket.connect("127.0.0.1:8081").await?;
loop {
let ready = socket.ready(Interest::READABLE | Interest::WRITABLE).await?;
if ready.is_readable() {
// The buffer is **not** included in the async task and will only exist
// on the stack.
let mut data = [0; 1024];
match socket.try_recv(&mut data[..]) {
Ok(n) => {
println!("received {:?}", &data[..n]);
}
// False-positive, continue
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
Err(e) => {
return Err(e);
}
}
}
if ready.is_writable() {
// Write some data
match socket.try_send(b"hello world") {
Ok(n) => {
println!("sent {} bytes", n);
}
// False-positive, continue
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
Err(e) => {
return Err(e);
}
}
}
}
}源代码pub async fn writable(&self) -> Result<()>
pub async fn writable(&self) -> Result<()>
等待套接字变为可写。
此函数等价于 ready(Interest::WRITABLE),通常与 try_send() 或 try_send_to() 配对使用。
该函数可能在套接字尚未可写时完成。这是一种误报,尝试调用 try_send() 将返回 io::ErrorKind::WouldBlock。
§取消安全性
此方法可安全取消。一旦就绪事件发生,该方法将继续立即返回,直到通过尝试写入而消费该就绪事件(失败时返回 WouldBlock 或 Poll::Pending)。
§示例
use tokio::net::UdpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
// Bind socket
let socket = UdpSocket::bind("127.0.0.1:8080").await?;
socket.connect("127.0.0.1:8081").await?;
loop {
// Wait for the socket to be writable
socket.writable().await?;
// Try to send data, this may still fail with `WouldBlock`
// if the readiness event is a false positive.
match socket.try_send(b"hello world") {
Ok(n) => {
break;
}
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e);
}
}
}
Ok(())
}源代码pub fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll<Result<()>>
pub fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll<Result<()>>
轮询写/发送就绪状态。
如果 UDP 流当前未准备好发送数据,此方法将存储来自所提供 Context 中的 Waker 的克隆。当 UDP 流变为可发送时,将在该 waker 上调用 Waker::wake。
请注意,在多次调用 poll_send_ready 或 poll_send 时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。(但是,poll_recv_ready 保留了一个独立的第二个唤醒器。)
此函数适用于无法通过 writable 创建并固定 future 的情况。在可能的情况下,优先使用 writable,因为它支持同时从多个任务进行轮询。
§返回值
函数返回:
Poll::Pendingif the udp stream is not ready for writing.Poll::Ready(Ok(()))if the udp stream is ready for writing.Poll::Ready(Err(e))if an error is encountered.
§错误
此函数可能遇到除 WouldBlock 之外的任何标准 I/O 错误。
源代码pub async fn send(&self, buf: &[u8]) -> Result<usize>
pub async fn send(&self, buf: &[u8]) -> Result<usize>
将数据发送到套接字所连接的远程地址。
connect 方法会将此套接字连接到远程地址。如果套接字未连接,此方法将失败。
如果远程地址对先前发送的数据包回复了 ICMP Unreachable,则此方法可能会失败并返回 ConnectionRefused 错误。但是,此行为取决于操作系统。
§返回值
成功时返回已发送的字节数,否则返回遇到的错误。
§取消安全性
此方法可安全取消。如果 send 在 tokio::select! 语句中作为事件使用,并且其他分支先完成,则可以保证该消息未被发送。
§示例
use tokio::io;
use tokio::net::UdpSocket;
#[tokio::main]
async fn main() -> io::Result<()> {
// Bind socket
let socket = UdpSocket::bind("127.0.0.1:8080").await?;
socket.connect("127.0.0.1:8081").await?;
// Send a message
socket.send(b"hello world").await?;
Ok(())
}源代码pub fn poll_send(&self, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>>
pub fn poll_send(&self, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>>
尝试将数据发送到套接字先前已 connect 的远程地址。
connect 方法会将此套接字连接到远程地址。如果套接字未连接,此方法将失败。
请注意,在 send 方向多次调用 poll_* 方法时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。
§返回值
函数返回:
Poll::Pendingif the socket is not available to writePoll::Ready(Ok(n))nis the number of bytes sentPoll::Ready(Err(e))if an error is encountered.
§错误
此函数可能遇到除 WouldBlock 之外的任何标准 I/O 错误。
源代码pub fn try_send(&self, buf: &[u8]) -> Result<usize>
pub fn try_send(&self, buf: &[u8]) -> Result<usize>
尝试将数据发送到套接字所连接的远程地址。
当套接字缓冲区已满时,返回 Err(io::ErrorKind::WouldBlock)。此函数通常与 writable() 配对使用。
§Returns
成功时返回 Ok(n),其中 n 是已发送的字节数。如果套接字未准备好发送数据,则返回 Err(ErrorKind::WouldBlock)。
§示例
use tokio::net::UdpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
// Bind a UDP socket
let socket = UdpSocket::bind("127.0.0.1:8080").await?;
// Connect to a peer
socket.connect("127.0.0.1:8081").await?;
loop {
// Wait for the socket to be writable
socket.writable().await?;
// Try to send data, this may still fail with `WouldBlock`
// if the readiness event is a false positive.
match socket.try_send(b"hello world") {
Ok(n) => {
break;
}
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e);
}
}
}
Ok(())
}源代码pub async fn readable(&self) -> Result<()>
pub async fn readable(&self) -> Result<()>
等待套接字变为可读。
此函数等价于 ready(Interest::READABLE),通常与 try_recv() 配对使用。
该函数可能在套接字尚未可读时完成。这是一种误报,尝试调用 try_recv() 将返回 io::ErrorKind::WouldBlock。
§取消安全性
此方法可安全取消。一旦就绪事件发生,该方法将继续立即返回,直到通过尝试读取而消费该就绪事件(失败时返回 WouldBlock 或 Poll::Pending)。
§示例
use tokio::net::UdpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
// Connect to a peer
let socket = UdpSocket::bind("127.0.0.1:8080").await?;
socket.connect("127.0.0.1:8081").await?;
loop {
// Wait for the socket to be readable
socket.readable().await?;
// The buffer is **not** included in the async task and will
// only exist on the stack.
let mut buf = [0; 1024];
// Try to recv data, this may still fail with `WouldBlock`
// if the readiness event is a false positive.
match socket.try_recv(&mut buf) {
Ok(n) => {
println!("GOT {:?}", &buf[..n]);
break;
}
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e);
}
}
}
Ok(())
}源代码pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll<Result<()>>
pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll<Result<()>>
轮询读/接收就绪状态。
如果 UDP 流当前未准备好接收数据,此方法将存储来自所提供 Context 中的 Waker 的克隆。当 UDP 套接字变为可读时,将在该 waker 上调用 Waker::wake。
请注意,在多次调用 poll_recv_ready、poll_recv 或 poll_peek 时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。(但是,poll_send_ready 保留了一个独立的第二个唤醒器。)
此函数适用于无法通过 readable 创建并固定 future 的情况。在可能的情况下,优先使用 readable,因为它支持同时从多个任务进行轮询。
§返回值
函数返回:
Poll::Pendingif the udp stream is not ready for reading.Poll::Ready(Ok(()))if the udp stream is ready for reading.Poll::Ready(Err(e))if an error is encountered.
§错误
此函数可能遇到除 WouldBlock 之外的任何标准 I/O 错误。
源代码pub async fn recv(&self, buf: &mut [u8]) -> Result<usize>
pub async fn recv(&self, buf: &mut [u8]) -> Result<usize>
从套接字所连接的远程地址接收单个数据报消息。成功时返回读取的字节数。
调用此函数时必须传入足够大小的有效字节数组 buf 以容纳消息字节。如果消息太长而无法装入提供的缓冲区,则多余字节可能会被丢弃。
connect 方法会将此套接字连接到远程地址。如果套接字未连接,此方法将失败。
§取消安全性
此方法可安全取消。如果 recv 在 tokio::select! 语句中作为事件使用,并且其他分支先完成,则可以保证此套接字没有接收到任何消息。
use tokio::net::UdpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
// Bind socket
let socket = UdpSocket::bind("127.0.0.1:8080").await?;
socket.connect("127.0.0.1:8081").await?;
let mut buf = vec![0; 10];
let n = socket.recv(&mut buf).await?;
println!("received {} bytes {:?}", n, &buf[..n]);
Ok(())
}源代码pub fn poll_recv(
&self,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<Result<()>>
pub fn poll_recv( &self, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<Result<()>>
尝试从套接字所 connect 的远程地址接收单个数据报消息。
connect 方法会将此套接字连接到远程地址。如果套接字未连接,此方法解析为错误。
请注意,在 recv 方向多次调用 poll_* 方法时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。
§返回值
函数返回:
Poll::Pendingif the socket is not ready to readPoll::Ready(Ok(()))reads dataReadBufif the socket is readyPoll::Ready(Err(e))if an error is encountered.
§错误
此函数可能遇到除 WouldBlock 之外的任何标准 I/O 错误。
源代码pub fn try_recv(&self, buf: &mut [u8]) -> Result<usize>
pub fn try_recv(&self, buf: &mut [u8]) -> Result<usize>
尝试从套接字所连接的远程地址接收单个数据报消息。成功时返回读取的字节数。
调用此方法时必须传入足够大小的有效字节数组 buf 以容纳消息字节。如果消息太长而无法装入提供的缓冲区,则多余字节可能会被丢弃。
当没有待处理数据时,返回 Err(io::ErrorKind::WouldBlock)。此函数通常与 readable() 配对使用。
§示例
use tokio::net::UdpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
// Connect to a peer
let socket = UdpSocket::bind("127.0.0.1:8080").await?;
socket.connect("127.0.0.1:8081").await?;
loop {
// Wait for the socket to be readable
socket.readable().await?;
// The buffer is **not** included in the async task and will
// only exist on the stack.
let mut buf = [0; 1024];
// Try to recv data, this may still fail with `WouldBlock`
// if the readiness event is a false positive.
match socket.try_recv(&mut buf) {
Ok(n) => {
println!("GOT {:?}", &buf[..n]);
break;
}
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e);
}
}
}
Ok(())
}源代码pub async fn send_to<A: ToSocketAddrs>(
&self,
buf: &[u8],
addr: A,
) -> Result<usize>
pub async fn send_to<A: ToSocketAddrs>( &self, buf: &[u8], addr: A, ) -> Result<usize>
将数据发送到套接字上的给定地址。成功时返回已写入的字节数。
地址类型可以是任何实现了 ToSocketAddrs trait 的类型。有关具体示例,请参阅其文档。
addr 可能会产生多个地址,但 send_to 只会将数据发送到 addr 产生的第一个地址。
当本地套接字的 IP 版本与 ToSocketAddrs 返回的不匹配时,将返回错误。
§取消安全性
此方法可安全取消。如果 send_to 在 tokio::select! 语句中作为事件使用,并且其他分支先完成,则可以保证该消息未被发送。
§示例
use tokio::net::UdpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
let socket = UdpSocket::bind("127.0.0.1:8080").await?;
let len = socket.send_to(b"hello world", "127.0.0.1:8081").await?;
println!("Sent {} bytes", len);
Ok(())
}源代码pub fn poll_send_to(
&self,
cx: &mut Context<'_>,
buf: &[u8],
target: SocketAddr,
) -> Poll<Result<usize>>
pub fn poll_send_to( &self, cx: &mut Context<'_>, buf: &[u8], target: SocketAddr, ) -> Poll<Result<usize>>
源代码pub fn try_send_to(&self, buf: &[u8], target: SocketAddr) -> Result<usize>
pub fn try_send_to(&self, buf: &[u8], target: SocketAddr) -> Result<usize>
尝试将数据发送到套接字上的给定地址,但如果发送被阻塞,此调用将立即返回。
此函数通常与 writable() 配对使用。
§Returns
成功时返回已发送的字节数
用户应确保在远程端无法接收时,ErrorKind::WouldBlock 得到正确处理。如果套接字的 IP 版本与 target 的 IP 版本不匹配,也会发生错误。
§示例
use tokio::net::UdpSocket;
use std::error::Error;
use std::io;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let socket = UdpSocket::bind("127.0.0.1:8080").await?;
let dst = "127.0.0.1:8081".parse()?;
loop {
socket.writable().await?;
match socket.try_send_to(&b"hello world"[..], dst) {
Ok(sent) => {
println!("sent {} bytes", sent);
break;
}
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
// Writable false positive.
continue;
}
Err(e) => return Err(e.into()),
}
}
Ok(())
}源代码pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)>
pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)>
在套接字上接收单个数据报消息。成功时返回读取的字节数和来源地址。
调用此函数时必须传入足够大小的有效字节数组 buf 以容纳消息字节。如果消息太长而无法装入提供的缓冲区,则多余字节可能会被丢弃。
§取消安全性
此方法可安全取消。如果 recv_from 在 tokio::select! 语句中作为事件使用,并且其他分支先完成,则可以保证此套接字没有接收到任何消息。
§示例
use tokio::net::UdpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
let socket = UdpSocket::bind("127.0.0.1:8080").await?;
let mut buf = vec![0u8; 32];
let (len, addr) = socket.recv_from(&mut buf).await?;
println!("received {:?} bytes from {:?}", len, addr);
Ok(())
}§注意
请注意,套接字地址不能被隐式信任,因为相对容易以伪造的源地址发送 UDP 数据报以实施数据包注入攻击。由于 UDP 是无状态的,并且不验证数据包的来源,攻击者无需拦截流量即可实施干扰。在设计应用层协议时,请务必了解这一点。
源代码pub fn poll_recv_from(
&self,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<Result<SocketAddr>>
pub fn poll_recv_from( &self, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<Result<SocketAddr>>
尝试在套接字上接收单个数据报。
请注意,在 recv 方向多次调用 poll_* 方法时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。
§返回值
函数返回:
Poll::Pendingif the socket is not ready to readPoll::Ready(Ok(addr))reads data fromaddrintoReadBufif the socket is readyPoll::Ready(Err(e))if an error is encountered.
§错误
此函数可能遇到除 WouldBlock 之外的任何标准 I/O 错误。
§注意
请注意,套接字地址不能被隐式信任,因为相对容易以伪造的源地址发送 UDP 数据报以实施数据包注入攻击。由于 UDP 是无状态的,并且不验证数据包的来源,攻击者无需拦截流量即可实施干扰。在设计应用层协议时,请务必了解这一点。
源代码pub fn try_recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)>
pub fn try_recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)>
尝试在套接字上接收单个数据报消息。成功时返回读取的字节数和来源地址。
调用此方法时必须传入足够大小的有效字节数组 buf 以容纳消息字节。如果消息太长而无法装入提供的缓冲区,则多余字节可能会被丢弃。
当没有待处理数据时,返回 Err(io::ErrorKind::WouldBlock)。此函数通常与 readable() 配对使用。
§注意
请注意,套接字地址不能被隐式信任,因为相对容易以伪造的源地址发送 UDP 数据报以实施数据包注入攻击。由于 UDP 是无状态的,并且不验证数据包的来源,攻击者无需拦截流量即可实施干扰。在设计应用层协议时,请务必了解这一点。
§示例
use tokio::net::UdpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
// Connect to a peer
let socket = UdpSocket::bind("127.0.0.1:8080").await?;
loop {
// Wait for the socket to be readable
socket.readable().await?;
// The buffer is **not** included in the async task and will
// only exist on the stack.
let mut buf = [0; 1024];
// Try to recv data, this may still fail with `WouldBlock`
// if the readiness event is a false positive.
match socket.try_recv_from(&mut buf) {
Ok((n, _addr)) => {
println!("GOT {:?}", &buf[..n]);
break;
}
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
continue;
}
Err(e) => {
return Err(e);
}
}
}
Ok(())
}源代码pub fn try_io<R>(
&self,
interest: Interest,
f: impl FnOnce() -> Result<R>,
) -> Result<R>
pub fn try_io<R>( &self, interest: Interest, f: impl FnOnce() -> Result<R>, ) -> Result<R>
尝试使用用户提供的 I/O 操作从套接字读取或写入数据。
如果套接字已就绪,则调用提供的闭包。闭包应通过手动调用适当的系统调用来尝试在套接字上执行 I/O 操作。如果操作失败的原因是套接字实际上尚未就绪,则闭包应返回 WouldBlock 错误,同时会清除就绪标志。闭包的返回值随后由 try_io 返回。
如果套接字未就绪,则不会调用闭包,并返回 WouldBlock 错误。
闭包仅在已对套接字执行了 I/O 操作且因套接字未就绪而失败时,才应返回 WouldBlock 错误。在其他任何情况下返回 WouldBlock 错误都会错误地清除就绪标志,可能导致套接字行为异常。
闭包不应使用 Tokio UdpSocket 类型上定义的任何方法来执行 I/O 操作,因为这会干扰就绪标志,并可能导致套接字行为异常。
此方法不应用于组合的就绪事件。闭包应当只执行一种 I/O 操作,因此不应需要多于一个的就绪状态。如果以组合的就绪事件调用,此方法可能会发生 panic 或永久休眠。
通常,readable()、writable() 或 ready() 与此函数配对使用。
源代码pub async fn async_io<R>(
&self,
interest: Interest,
f: impl FnMut() -> Result<R>,
) -> Result<R>
pub async fn async_io<R>( &self, interest: Interest, f: impl FnMut() -> Result<R>, ) -> Result<R>
使用用户提供的 I/O 操作从套接字读取或写入数据。
会等待套接字的就绪状态,当套接字就绪时,会调用提供的闭包。闭包应通过手动调用适当的系统调用来尝试在套接字上执行 I/O 操作。如果操作失败的原因是套接字实际上尚未就绪,则闭包应返回 WouldBlock 错误。在这种情况下,会清除就绪标志并重新等待套接字就绪。该循环将一直重复,直到闭包返回 Ok 或除 WouldBlock 之外的错误。
闭包仅在已对套接字执行了 I/O 操作且因套接字未就绪而失败时,才应返回 WouldBlock 错误。在其他任何情况下返回 WouldBlock 错误都会错误地清除就绪标志,可能导致套接字行为异常。
闭包不应使用 Tokio UdpSocket 类型上定义的任何方法来执行 I/O 操作,因为这会干扰就绪标志,并可能导致套接字行为异常。
此方法不应用于组合的就绪事件。闭包应当只执行一种 I/O 操作,因此不应需要多于一个的就绪状态。如果以组合的就绪事件调用,此方法可能会发生 panic 或永久休眠。
源代码pub async fn peek(&self, buf: &mut [u8]) -> Result<usize>
pub async fn peek(&self, buf: &mut [u8]) -> Result<usize>
从已连接的地址接收单个数据报,但不会将其从队列中移除。成功时返回读取的字节数以及数据的来源地址。
§注意
在 Windows 上,如果数据大于指定的缓冲区,则缓冲区会被填满数据的开头部分,peek 返回错误 WSAEMSGSIZE(10040)。多余的数据将丢失。请务必使用足够大的缓冲区以容纳最大 UDP 数据包(可达 65536 字节)。
如果传入零大小的缓冲区,macOS 将返回错误。
如果你只想了解队列头部数据的发送方,请尝试 peek_sender。
请注意,套接字地址不能被隐式信任,因为相对容易以伪造的源地址发送 UDP 数据报以实施数据包注入攻击。由于 UDP 是无状态的,并且不验证数据包的来源,攻击者无需拦截流量即可实施干扰。在设计应用层协议时,请务必了解这一点。
§示例
use tokio::net::UdpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
let socket = UdpSocket::bind("127.0.0.1:8080").await?;
let mut buf = vec![0u8; 32];
let len = socket.peek(&mut buf).await?;
println!("peeked {:?} bytes", len);
Ok(())
}源代码pub fn poll_peek(
&self,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<Result<()>>
pub fn poll_peek( &self, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<Result<()>>
从已连接的地址接收数据,但不会将其从输入队列中移除。
§注意
请注意,在 recv 方向多次调用 poll_* 方法时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。
在 Windows 上,如果数据大于指定的缓冲区,则缓冲区会被填满数据的开头部分,peek 返回错误 WSAEMSGSIZE(10040)。多余的数据将丢失。请务必使用足够大的缓冲区以容纳最大 UDP 数据包(可达 65536 字节)。
如果传入零大小的缓冲区,macOS 将返回错误。
如果你只想了解队列头部数据的发送方,请尝试 poll_peek_sender。
请注意,套接字地址不能被隐式信任,因为相对容易以伪造的源地址发送 UDP 数据报以实施数据包注入攻击。由于 UDP 是无状态的,并且不验证数据包的来源,攻击者无需拦截流量即可实施干扰。在设计应用层协议时,请务必了解这一点。
§返回值
函数返回:
Poll::Pendingif the socket is not ready to readPoll::Ready(Ok(()))reads data intoReadBufif the socket is readyPoll::Ready(Err(e))if an error is encountered.
§错误
此函数可能遇到除 WouldBlock 之外的任何标准 I/O 错误。
源代码pub fn try_peek(&self, buf: &mut [u8]) -> Result<usize>
pub fn try_peek(&self, buf: &mut [u8]) -> Result<usize>
尝试从已连接的地址接收数据,但不会将其从输入队列中移除。成功时返回读取的字节数。
当没有待处理数据时,返回 Err(io::ErrorKind::WouldBlock)。此函数通常与 readable() 配对使用。
§注意
在 Windows 上,如果数据大于指定的缓冲区,则缓冲区会被填满数据的开头部分,peek 返回错误 WSAEMSGSIZE(10040)。多余的数据将丢失。请务必使用足够大的缓冲区以容纳最大 UDP 数据包(可达 65536 字节)。
如果传入零大小的缓冲区,macOS 将返回错误。
如果你只想了解队列头部数据的发送方,请尝试 try_peek_sender。
请注意,套接字地址不能被隐式信任,因为相对容易以伪造的源地址发送 UDP 数据报以实施数据包注入攻击。由于 UDP 是无状态的,并且不验证数据包的来源,攻击者无需拦截流量即可实施干扰。在设计应用层协议时,请务必了解这一点。
源代码pub async fn peek_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)>
pub async fn peek_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)>
从套接字接收数据,但不会将其从输入队列中移除。成功时返回读取的字节数以及数据来源的地址。
§注意
在 Windows 上,如果数据大于指定的缓冲区,则缓冲区会被填满数据的开头部分,peek_from 返回错误 WSAEMSGSIZE(10040)。多余的数据将丢失。请务必使用足够大的缓冲区以容纳最大 UDP 数据包(可达 65536 字节)。
如果传入零大小的缓冲区,macOS 将返回错误。
如果你只想了解队列头部数据的发送方,请尝试 peek_sender。
请注意,套接字地址不能被隐式信任,因为相对容易以伪造的源地址发送 UDP 数据报以实施数据包注入攻击。由于 UDP 是无状态的,并且不验证数据包的来源,攻击者无需拦截流量即可实施干扰。在设计应用层协议时,请务必了解这一点。
§示例
use tokio::net::UdpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
let socket = UdpSocket::bind("127.0.0.1:8080").await?;
let mut buf = vec![0u8; 32];
let (len, addr) = socket.peek_from(&mut buf).await?;
println!("peeked {:?} bytes from {:?}", len, addr);
Ok(())
}源代码pub fn poll_peek_from(
&self,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<Result<SocketAddr>>
pub fn poll_peek_from( &self, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<Result<SocketAddr>>
从套接字接收数据,但不会将其从输入队列中移除。成功时返回数据报的发送地址。
§注意
请注意,在 recv 方向多次调用 poll_* 方法时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。
在 Windows 上,如果数据大于指定的缓冲区,则缓冲区会被填满数据的开头部分,peek 返回错误 WSAEMSGSIZE(10040)。多余的数据将丢失。请务必使用足够大的缓冲区以容纳最大 UDP 数据包(可达 65536 字节)。
如果传入零大小的缓冲区,macOS 将返回错误。
如果你只想了解队列头部数据的发送方,请尝试 poll_peek_sender。
请注意,套接字地址不能被隐式信任,因为相对容易以伪造的源地址发送 UDP 数据报以实施数据包注入攻击。由于 UDP 是无状态的,并且不验证数据包的来源,攻击者无需拦截流量即可实施干扰。在设计应用层协议时,请务必了解这一点。
§返回值
函数返回:
Poll::Pendingif the socket is not ready to readPoll::Ready(Ok(addr))reads data fromaddrintoReadBufif the socket is readyPoll::Ready(Err(e))if an error is encountered.
§错误
此函数可能遇到除 WouldBlock 之外的任何标准 I/O 错误。
源代码pub fn try_peek_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)>
pub fn try_peek_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)>
尝试从套接字接收数据,但不会将其从输入队列中移除。成功时返回读取的字节数和数据报的发送地址。
当没有待处理数据时,返回 Err(io::ErrorKind::WouldBlock)。此函数通常与 readable() 配对使用。
§注意
在 Windows 上,如果数据大于指定的缓冲区,则缓冲区会被填满数据的开头部分,peek 返回错误 WSAEMSGSIZE(10040)。多余的数据将丢失。请务必使用足够大的缓冲区以容纳最大 UDP 数据包(可达 65536 字节)。
如果传入零大小的缓冲区,macOS 将返回错误。
如果你只想了解队列头部数据的发送方,请尝试 try_peek_sender。
请注意,套接字地址不能被隐式信任,因为相对容易以伪造的源地址发送 UDP 数据报以实施数据包注入攻击。由于 UDP 是无状态的,并且不验证数据包的来源,攻击者无需拦截流量即可实施干扰。在设计应用层协议时,请务必了解这一点。
源代码pub async fn peek_sender(&self) -> Result<SocketAddr>
pub async fn peek_sender(&self) -> Result<SocketAddr>
源代码pub fn poll_peek_sender(&self, cx: &mut Context<'_>) -> Poll<Result<SocketAddr>>
pub fn poll_peek_sender(&self, cx: &mut Context<'_>) -> Poll<Result<SocketAddr>>
检索输入队列头部数据的发送方,如果队列为空则调度唤醒。
这等效于使用零大小的缓冲区调用 poll_peek_from,但会抑制 Windows 上的 WSAEMSGSIZE 错误和 macOS 上的 “invalid argument” 错误。
§注意
请注意,在 recv 方向多次调用 poll_* 方法时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。
请注意,套接字地址不能被隐式信任,因为相对容易以伪造的源地址发送 UDP 数据报以实施数据包注入攻击。由于 UDP 是无状态的,并且不验证数据包的来源,攻击者无需拦截流量即可实施干扰。在设计应用层协议时,请务必了解这一点。
源代码pub fn try_peek_sender(&self) -> Result<SocketAddr>
pub fn try_peek_sender(&self) -> Result<SocketAddr>
尝试检索输入队列头部数据的发送方。
当没有待处理数据时,返回 Err(io::ErrorKind::WouldBlock)。此函数通常与 readable() 配对使用。
请注意,套接字地址不能被隐式信任,因为相对容易以伪造的源地址发送 UDP 数据报以实施数据包注入攻击。由于 UDP 是无状态的,并且不验证数据包的来源,攻击者无需拦截流量即可实施干扰。在设计应用层协议时,请务必了解这一点。
源代码pub fn broadcast(&self) -> Result<bool>
pub fn broadcast(&self) -> Result<bool>
获取此套接字的 SO_BROADCAST 选项的值。
有关此选项的更多信息,请参阅 set_broadcast。
源代码pub fn set_broadcast(&self, on: bool) -> Result<()>
pub fn set_broadcast(&self, on: bool) -> Result<()>
设置此套接字上 SO_BROADCAST 选项的值。
启用后,此套接字将允许向广播地址发送数据包。
源代码pub fn multicast_loop_v4(&self) -> Result<bool>
pub fn multicast_loop_v4(&self) -> Result<bool>
获取此套接字的 IP_MULTICAST_LOOP 选项的值。
有关此选项的更多信息,请参阅 set_multicast_loop_v4。
源代码pub fn set_multicast_loop_v4(&self, on: bool) -> Result<()>
pub fn set_multicast_loop_v4(&self, on: bool) -> Result<()>
源代码pub fn multicast_ttl_v4(&self) -> Result<u32>
pub fn multicast_ttl_v4(&self) -> Result<u32>
获取此套接字的 IP_MULTICAST_TTL 选项的值。
有关此选项的更多信息,请参阅 set_multicast_ttl_v4。
源代码pub fn set_multicast_ttl_v4(&self, ttl: u32) -> Result<()>
pub fn set_multicast_ttl_v4(&self, ttl: u32) -> Result<()>
设置此套接字上 IP_MULTICAST_TTL 选项的值。
指示此套接字对外发送的多播数据包的生存时间值。默认值为 1,这意味着多播数据包除非明确要求,否则不会离开本地网络。
§注意
这可能对 IPv6 套接字没有任何效果。
源代码pub fn multicast_loop_v6(&self) -> Result<bool>
pub fn multicast_loop_v6(&self) -> Result<bool>
获取此套接字的 IPV6_MULTICAST_LOOP 选项的值。
有关此选项的更多信息,请参阅 set_multicast_loop_v6。
源代码pub fn set_multicast_loop_v6(&self, on: bool) -> Result<()>
pub fn set_multicast_loop_v6(&self, on: bool) -> Result<()>
源代码pub fn set_ttl(&self, ttl: u32) -> Result<()>
pub fn set_ttl(&self, ttl: u32) -> Result<()>
设置此套接字上 IP_TTL 选项的值。
此值设置从此套接字发送的每个数据包中使用的生存时间字段。
§示例
use tokio::net::UdpSocket;
let sock = UdpSocket::bind("127.0.0.1:8080").await?;
sock.set_ttl(60)?;
源代码pub fn tos_v4(&self) -> Result<u32>
pub fn tos_v4(&self) -> Result<u32>
获取此套接字的 IP_TOS 选项的值。
有关此选项的更多信息,请参阅 set_tos_v4。
源代码pub fn set_tos_v4(&self, tos: u32) -> Result<()>
pub fn set_tos_v4(&self, tos: u32) -> Result<()>
设置此套接字上 IP_TOS 选项的值。
此值设置从此套接字发送的每个数据包中使用的服务类型字段。
§注意
- This may not have any effect on IPv6 sockets.
- On Windows,
IP_TOSis only supported on Windows 8+ or Windows Server 2012+.
源代码pub fn join_multicast_v4(
&self,
multiaddr: Ipv4Addr,
interface: Ipv4Addr,
) -> Result<()>
pub fn join_multicast_v4( &self, multiaddr: Ipv4Addr, interface: Ipv4Addr, ) -> Result<()>
执行 IP_ADD_MEMBERSHIP 类型的操作。
此函数为此套接字要加入的多播组指定一个新地址。地址必须是有效的多播地址,interface 是系统应使用其加入多播组的本地接口的地址。如果它等于 INADDR_ANY,则系统会选择一个合适的接口。
源代码pub fn join_multicast_v6(
&self,
multiaddr: &Ipv6Addr,
interface: u32,
) -> Result<()>
pub fn join_multicast_v6( &self, multiaddr: &Ipv6Addr, interface: u32, ) -> Result<()>
执行 IPV6_ADD_MEMBERSHIP 类型的操作。
此函数为此套接字要加入的多播组指定一个新地址。地址必须是有效的多播地址,interface 是要加入/离开的接口的索引(或 0 表示任意接口)。
源代码pub fn leave_multicast_v4(
&self,
multiaddr: Ipv4Addr,
interface: Ipv4Addr,
) -> Result<()>
pub fn leave_multicast_v4( &self, multiaddr: Ipv4Addr, interface: Ipv4Addr, ) -> Result<()>
执行 IP_DROP_MEMBERSHIP 类型的操作。
有关此选项的更多信息,请参阅 join_multicast_v4。
源代码pub fn leave_multicast_v6(
&self,
multiaddr: &Ipv6Addr,
interface: u32,
) -> Result<()>
pub fn leave_multicast_v6( &self, multiaddr: &Ipv6Addr, interface: u32, ) -> Result<()>
执行 IPV6_DROP_MEMBERSHIP 类型的操作。
有关此选项的更多信息,请参阅 join_multicast_v6。
源代码pub fn take_error(&self) -> Result<Option<Error>>
pub fn take_error(&self) -> Result<Option<Error>>
返回 SO_ERROR 选项的值。
§示例
use tokio::net::UdpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
// Create a socket
let socket = UdpSocket::bind("0.0.0.0:8080").await?;
if let Ok(Some(err)) = socket.take_error() {
println!("Got error: {:?}", err);
}
Ok(())
}trait 实现§
源代码§impl AsRawSocket for UdpSocket
Available on docsrs, or Windows only.
impl AsRawSocket for UdpSocket
docsrs, or Windows only.