You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测UDP目标Socket未处于监听状态?

问题:UDP发送无报错,如何检测目标Socket未处于监听状态?

我尝试通过UDP发送数据,发送操作可正常执行,但即使目标Socket不存在也不会触发报错。请问有没有办法检测目标Socket未处于监听状态?

我使用了如下代码,端口8081没有任何监听服务,但发送时完全无报错;而用Python执行相同操作时,会收到“Connection refused”错误提示。

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);
            }
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                // Writable false positive.
                println!("{e}");
            }
            Err(e) => return Err(e.into()),
        }
    }

    Ok(())
}

更新说明:已根据Steffen的评论更新代码,但向未监听端口发送UDP消息仍无报错。


解答

UDP是无连接协议,发送方发送数据时不需要和目标建立连接,操作系统只会把数据包交给网络层,不会主动验证目标端口是否有监听服务——这就是你发送无报错的核心原因。

为什么Python会报错?

Python里的UDP操作出现"Connection refused",通常是因为先调用了connect()绑定目标地址,此时操作系统会尝试发送隐式的连接探测(ICMP端口不可达包),收到该报文后才会抛出错误。而你的Rust代码用try_send_to属于无连接发送,不会触发这个探测逻辑。

检测目标端口是否监听的可行方案:

  • 主动触发ICMP探测:
    先调用socket.connect(dst).await将UDP套接字与目标地址绑定,之后再发送数据。如果目标端口无监听,操作系统会收到ICMP的"端口不可达"报文,后续的发送或读取操作会返回错误。注意,这个错误不会在第一次发送时立刻出现,因为ICMP报文返回有延迟,需要在后续操作中捕获。
    修改后的代码示例:
    use tokio::net::UdpSocket;
    use std::error::Error;
    use std::io;
    use tokio::time::{sleep, Duration};
    
    #[tokio::main]
    async fn main() -> Result<(), Box<dyn Error>> {
        let mut socket = UdpSocket::bind("127.0.0.1:8080").await?;
        let dst = "127.0.0.1:8081".parse()?;
    
        // 绑定目标地址,触发ICMP探测机制
        socket.connect(dst).await?;
    
        loop {
            socket.writable().await?;
    
            match socket.try_send(&b"hello world"[..]) {
                Ok(sent) => {
                    println!("sent {} bytes", sent);
                    // 尝试读取ICMP错误信息
                    let mut buf = [0; 1024];
                    match socket.try_recv(&mut buf) {
                        Err(e) if e.kind() == io::ErrorKind::ConnectionRefused => {
                            return Err(e.into());
                        }
                        _ => {}
                    }
                }
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                    println!("{e}");
                }
                Err(e) => return Err(e.into()),
            }
            sleep(Duration::from_secs(1)).await;
        }
    }
    
  • TCP握手探测:
    临时创建TCP套接字尝试与目标端口建立连接,若连接失败(如Connection refused),则说明目标端口无监听服务。这种方式更直接,但依赖TCP协议,和UDP本身无关。

注意事项:

  • ICMP报文可能被防火墙拦截,导致无法收到"端口不可达"通知,此时即使目标无监听,发送操作也不会报错。
  • UDP的无连接特性决定了它无法100%保证数据送达,即使检测到目标端口开放,也不能确保数据一定能被接收方处理。

内容的提问来源于stack exchange,提问作者MarieGosnell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 01:11:23