跳到主要内容

UdpSocket

搜索

结构体 UdpSocket 

源代码
pub struct UdpSocket { /* 私有字段 */ }
展开描述

一个 UDP 套接字。

UDP 与 TCP 不同,是“无连接”的。这意味着,无论你绑定到什么地址,UdpSocket 都可以自由地与许多不同的远程端通信。在 Tokio 中,基本上有两种主要的使用 UdpSocket 的方式:

  • one to many: bind and use send_to and recv_from to communicate with many different addresses
  • one to one: connect and associate with a single address, using send and recv to 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,我们可以使用 sendrecv 与单个远程地址进行 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_torecv_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

源代码

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>

从先前已绑定的 std::net::UdpSocket 创建一个新的 UdpSocket

此函数旨在将标准库的 UDP 套接字包装为其 Tokio 等价物。

这可与 socket2Socket 接口配合使用,以便在套接字被移交之前对其进行配置,例如设置 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>

将一个 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>

返回此套接字绑定的本地地址。

§示例
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>

返回此套接字所连接到的远程对等方的套接字地址。

§示例
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<()>

连接此 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>

等待任何所请求的就绪状态。

此函数通常与 try_recv()try_send() 配对使用。它可用于在单个任务上同时对同一套接字进行 recv / send,而无需拆分套接字。

该函数可能在套接字尚未就绪时完成。这是一种误报,尝试进行操作将返回 io::ErrorKind::WouldBlock。该函数也可能返回空的 Ready 集合,因此应始终检查返回值,如果请求的状态未设置,可能需要再次等待。

§取消安全性

此方法可安全取消。一旦就绪事件发生,该方法将继续立即返回,直到通过尝试读取或写入而消费该就绪事件(失败时返回 WouldBlockPoll::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<()>

等待套接字变为可写。

此函数等价于 ready(Interest::WRITABLE),通常与 try_send()try_send_to() 配对使用。

该函数可能在套接字尚未可写时完成。这是一种误报,尝试调用 try_send() 将返回 io::ErrorKind::WouldBlock

§取消安全性

此方法可安全取消。一旦就绪事件发生,该方法将继续立即返回,直到通过尝试写入而消费该就绪事件(失败时返回 WouldBlockPoll::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<()>>

轮询写/发送就绪状态。

如果 UDP 流当前未准备好发送数据,此方法将存储来自所提供 Context 中的 Waker 的克隆。当 UDP 流变为可发送时,将在该 waker 上调用 Waker::wake

请注意,在多次调用 poll_send_readypoll_send 时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。(但是,poll_recv_ready 保留了一个独立的第二个唤醒器。)

此函数适用于无法通过 writable 创建并固定 future 的情况。在可能的情况下,优先使用 writable,因为它支持同时从多个任务进行轮询。

§返回值

函数返回:

  • Poll::Pending if 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>

将数据发送到套接字所连接的远程地址。

connect 方法会将此套接字连接到远程地址。如果套接字未连接,此方法将失败。

如果远程地址对先前发送的数据包回复了 ICMP Unreachable,则此方法可能会失败并返回 ConnectionRefused 错误。但是,此行为取决于操作系统。

§返回值

成功时返回已发送的字节数,否则返回遇到的错误。

§取消安全性

此方法可安全取消。如果 sendtokio::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>>

尝试将数据发送到套接字先前已 connect 的远程地址。

connect 方法会将此套接字连接到远程地址。如果套接字未连接,此方法将失败。

请注意,在 send 方向多次调用 poll_* 方法时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。

§返回值

函数返回:

  • Poll::Pending if the socket is not available to write
  • Poll::Ready(Ok(n)) n is the number of bytes sent
  • Poll::Ready(Err(e)) if an error is encountered.
§错误

此函数可能遇到除 WouldBlock 之外的任何标准 I/O 错误。

源代码

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<()>

等待套接字变为可读。

此函数等价于 ready(Interest::READABLE),通常与 try_recv() 配对使用。

该函数可能在套接字尚未可读时完成。这是一种误报,尝试调用 try_recv() 将返回 io::ErrorKind::WouldBlock

§取消安全性

此方法可安全取消。一旦就绪事件发生,该方法将继续立即返回,直到通过尝试读取而消费该就绪事件(失败时返回 WouldBlockPoll::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<()>>

轮询读/接收就绪状态。

如果 UDP 流当前未准备好接收数据,此方法将存储来自所提供 Context 中的 Waker 的克隆。当 UDP 套接字变为可读时,将在该 waker 上调用 Waker::wake

请注意,在多次调用 poll_recv_readypoll_recvpoll_peek 时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。(但是,poll_send_ready 保留了一个独立的第二个唤醒器。)

此函数适用于无法通过 readable 创建并固定 future 的情况。在可能的情况下,优先使用 readable,因为它支持同时从多个任务进行轮询。

§返回值

函数返回:

  • Poll::Pending if 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>

从套接字所连接的远程地址接收单个数据报消息。成功时返回读取的字节数。

调用此函数时必须传入足够大小的有效字节数组 buf 以容纳消息字节。如果消息太长而无法装入提供的缓冲区,则多余字节可能会被丢弃。

connect 方法会将此套接字连接到远程地址。如果套接字未连接,此方法将失败。

§取消安全性

此方法可安全取消。如果 recvtokio::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<()>>

尝试从套接字所 connect 的远程地址接收单个数据报消息。

connect 方法会将此套接字连接到远程地址。如果套接字未连接,此方法解析为错误。

请注意,在 recv 方向多次调用 poll_* 方法时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。

§返回值

函数返回:

  • Poll::Pending if the socket is not ready to read
  • Poll::Ready(Ok(())) reads data ReadBuf if the socket is ready
  • Poll::Ready(Err(e)) if an error is encountered.
§错误

此函数可能遇到除 WouldBlock 之外的任何标准 I/O 错误。

源代码

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>

将数据发送到套接字上的给定地址。成功时返回已写入的字节数。

地址类型可以是任何实现了 ToSocketAddrs trait 的类型。有关具体示例,请参阅其文档。

addr 可能会产生多个地址,但 send_to 只会将数据发送到 addr 产生的第一个地址。

当本地套接字的 IP 版本与 ToSocketAddrs 返回的不匹配时,将返回错误。

§取消安全性

此方法可安全取消。如果 send_totokio::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>>

尝试将数据发送到套接字上的给定地址。

请注意,在 send 方向多次调用 poll_* 方法时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。

§返回值

函数返回:

  • Poll::Pending if the socket is not ready to write
  • Poll::Ready(Ok(n)) n is the number of bytes sent.
  • Poll::Ready(Err(e)) if an error is encountered.
§错误

此函数可能遇到除 WouldBlock 之外的任何标准 I/O 错误。

源代码

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)>

在套接字上接收单个数据报消息。成功时返回读取的字节数和来源地址。

调用此函数时必须传入足够大小的有效字节数组 buf 以容纳消息字节。如果消息太长而无法装入提供的缓冲区,则多余字节可能会被丢弃。

§取消安全性

此方法可安全取消。如果 recv_fromtokio::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>>

尝试在套接字上接收单个数据报。

请注意,在 recv 方向多次调用 poll_* 方法时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。

§返回值

函数返回:

  • Poll::Pending if the socket is not ready to read
  • Poll::Ready(Ok(addr)) reads data from addr into ReadBuf if the socket is ready
  • Poll::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)>

尝试在套接字上接收单个数据报消息。成功时返回读取的字节数和来源地址。

调用此方法时必须传入足够大小的有效字节数组 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>

尝试使用用户提供的 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>

使用用户提供的 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>

从已连接的地址接收单个数据报,但不会将其从队列中移除。成功时返回读取的字节数以及数据的来源地址。

§注意

在 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<()>>

从已连接的地址接收数据,但不会将其从输入队列中移除。

§注意

请注意,在 recv 方向多次调用 poll_* 方法时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。

在 Windows 上,如果数据大于指定的缓冲区,则缓冲区会被填满数据的开头部分,peek 返回错误 WSAEMSGSIZE(10040)。多余的数据将丢失。请务必使用足够大的缓冲区以容纳最大 UDP 数据包(可达 65536 字节)。

如果传入零大小的缓冲区,macOS 将返回错误。

如果你只想了解队列头部数据的发送方,请尝试 poll_peek_sender

请注意,套接字地址不能被隐式信任,因为相对容易以伪造的源地址发送 UDP 数据报以实施数据包注入攻击。由于 UDP 是无状态的,并且不验证数据包的来源,攻击者无需拦截流量即可实施干扰。在设计应用层协议时,请务必了解这一点。

§返回值

函数返回:

  • Poll::Pending if the socket is not ready to read
  • Poll::Ready(Ok(())) reads data into ReadBuf if the socket is ready
  • Poll::Ready(Err(e)) if an error is encountered.
§错误

此函数可能遇到除 WouldBlock 之外的任何标准 I/O 错误。

源代码

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)>

从套接字接收数据,但不会将其从输入队列中移除。成功时返回读取的字节数以及数据来源的地址。

§注意

在 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>>

从套接字接收数据,但不会将其从输入队列中移除。成功时返回数据报的发送地址。

§注意

请注意,在 recv 方向多次调用 poll_* 方法时,只有传递给最近一次调用的 Context 中的 Waker 才会被调度以接收唤醒。

在 Windows 上,如果数据大于指定的缓冲区,则缓冲区会被填满数据的开头部分,peek 返回错误 WSAEMSGSIZE(10040)。多余的数据将丢失。请务必使用足够大的缓冲区以容纳最大 UDP 数据包(可达 65536 字节)。

如果传入零大小的缓冲区,macOS 将返回错误。

如果你只想了解队列头部数据的发送方,请尝试 poll_peek_sender

请注意,套接字地址不能被隐式信任,因为相对容易以伪造的源地址发送 UDP 数据报以实施数据包注入攻击。由于 UDP 是无状态的,并且不验证数据包的来源,攻击者无需拦截流量即可实施干扰。在设计应用层协议时,请务必了解这一点。

§返回值

函数返回:

  • Poll::Pending if the socket is not ready to read
  • Poll::Ready(Ok(addr)) reads data from addr into ReadBuf if the socket is ready
  • Poll::Ready(Err(e)) if an error is encountered.
§错误

此函数可能遇到除 WouldBlock 之外的任何标准 I/O 错误。

源代码

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>

检索输入队列头部数据的发送方,如果队列为空则等待。

这等效于使用零大小的缓冲区调用 peek_from,但会抑制 Windows 上的 WSAEMSGSIZE 错误和 macOS 上的 “invalid argument” 错误。

请注意,套接字地址不能被隐式信任,因为相对容易以伪造的源地址发送 UDP 数据报以实施数据包注入攻击。由于 UDP 是无状态的,并且不验证数据包的来源,攻击者无需拦截流量即可实施干扰。在设计应用层协议时,请务必了解这一点。

源代码

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>

尝试检索输入队列头部数据的发送方。

当没有待处理数据时,返回 Err(io::ErrorKind::WouldBlock)。此函数通常与 readable() 配对使用。

请注意,套接字地址不能被隐式信任,因为相对容易以伪造的源地址发送 UDP 数据报以实施数据包注入攻击。由于 UDP 是无状态的,并且不验证数据包的来源,攻击者无需拦截流量即可实施干扰。在设计应用层协议时,请务必了解这一点。

源代码

pub fn broadcast(&self) -> Result<bool>

获取此套接字的 SO_BROADCAST 选项的值。

有关此选项的更多信息,请参阅 set_broadcast

源代码

pub fn set_broadcast(&self, on: bool) -> Result<()>

设置此套接字上 SO_BROADCAST 选项的值。

启用后,此套接字将允许向广播地址发送数据包。

源代码

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<()>

设置此套接字上 IP_MULTICAST_LOOP 选项的值。

如果启用,多播数据包将被环回到本地套接字。

§注意

这可能对 IPv6 套接字没有任何效果。

源代码

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<()>

设置此套接字上 IP_MULTICAST_TTL 选项的值。

指示此套接字对外发送的多播数据包的生存时间值。默认值为 1,这意味着多播数据包除非明确要求,否则不会离开本地网络。

§注意

这可能对 IPv6 套接字没有任何效果。

源代码

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<()>

设置此套接字上 IPV6_MULTICAST_LOOP 选项的值。

控制此套接字是否能看见它自己发送的多播数据包。

§注意

这对 IPv4 套接字可能没有任何影响。

源代码

pub fn ttl(&self) -> Result<u32>

获取此套接字的 IP_TTL 选项的值。

有关此选项的更多信息,请参阅 set_ttl

§示例
use tokio::net::UdpSocket;

let sock = UdpSocket::bind("127.0.0.1:8080").await?;

println!("{:?}", sock.ttl()?);
源代码

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>

获取此套接字的 IP_TOS 选项的值。

有关此选项的更多信息,请参阅 set_tos_v4

源代码

pub fn set_tos_v4(&self, tos: u32) -> Result<()>

设置此套接字上 IP_TOS 选项的值。

此值设置从此套接字发送的每个数据包中使用的服务类型字段。

§注意
源代码

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<()>

执行 IPV6_ADD_MEMBERSHIP 类型的操作。

此函数为此套接字要加入的多播组指定一个新地址。地址必须是有效的多播地址,interface 是要加入/离开的接口的索引(或 0 表示任意接口)。

源代码

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<()>

执行 IPV6_DROP_MEMBERSHIP 类型的操作。

有关此选项的更多信息,请参阅 join_multicast_v6

源代码

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.
源代码§

fn as_raw_socket(&self) -> RawSocket

Extracts the raw socket. 更多信息
源代码§

impl AsSocket for UdpSocket

Available on docsrs, or Windows only.
源代码§

fn as_socket(&self) -> BorrowedSocket<'_>

借用此套接字。
源代码§

impl Debug for UdpSocket

源代码§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

使用给定的格式化器格式化此值。 更多信息
源代码§

impl TryFrom<UdpSocket> for UdpSocket

源代码§

fn try_from(stream: UdpSocket) -> Result<Self, Self::Error>

消耗流,返回 Tokio 的 I/O 对象。

这等效于 UdpSocket::from_std(stream)

源代码§

type Error = Error

转换出错时返回的类型。

自动 trait 实现§

blanket 实现§

源代码§

impl<T> Any for T
where T: 'static + ?Sized,

源代码§

fn type_id(&self) -> TypeId

Gets the TypeId of self. 更多信息
源代码§

impl<T> Borrow<T> for T
where T: ?Sized,

源代码§

fn borrow(&self) -> &T

Immutably borrows from an owned value. 更多信息
源代码§

impl<T> BorrowMut<T> for T
where T: ?Sized,

源代码§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. 更多信息
源代码§

impl<T> From<T> for T

源代码§

fn from(t: T) -> T

原样返回参数。

源代码§

impl<T, U> Into<U> for T
where U: From<T>,

源代码§

fn into(self) -> U

调用 U::from(self)

也就是说,此转换是 From<T> for U 实现选择执行的操作。

源代码§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

源代码§

type Error = Infallible

转换出错时返回的类型。
源代码§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

执行转换。
源代码§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

源代码§

type Error = <U as TryFrom<T>>::Error

转换出错时返回的类型。
源代码§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

执行转换。