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

非阻塞Unix数据报读取出现"Resource temporarily unavailable"错误

问题解决与非阻塞读取实现

错误根源

你遇到的WouldBlock错误是非阻塞IO的正常行为:当socket设置为非阻塞模式后,调用recv()时如果没有数据可读,系统会返回这个错误,而你直接用unwrap()把它当成致命错误处理,导致程序panic。

解决方案

核心修改

  1. 移除set_read_timeout:非阻塞模式下不需要超时设置,两者混用会导致逻辑混乱。
  2. 替换recv().unwrap()为错误匹配逻辑,专门处理WouldBlock,实现你要的try_read式循环。
  3. 自动清理socket文件,避免手动删除的麻烦。

修改后完整代码

#![feature(duration_constants)]
use std::os::unix::net::UnixDatagram;
use std::time::Duration;
use std::io;

const OLD_PROCESS: &str = "./old";
const NEW_PROCESS: &str = "./new";

fn startup() {
    let socket = UnixDatagram::bind(NEW_PROCESS).unwrap();

    println!("sending shutdown signal");
    socket.send_to(&[1], OLD_PROCESS).unwrap();
    println!("sent shutdown signal");

    println!("receiving data");
    let mut data = [Default::default(); 4];
    // 启动流程需要阻塞等待数据,unwrap安全
    socket.recv(&mut data).unwrap();
    println!("data: {:?}", data);

    // 确保文件被删除,忽略删除失败(比如已被其他进程删除)
    let _ = std::fs::remove_file(NEW_PROCESS);
}

fn process() {
    let socket = UnixDatagram::bind(OLD_PROCESS).unwrap();
    // 使用scopeguard自动清理socket文件,无需手动删除
    let _cleanup_guard = scopeguard::guard((), |_| {
        let _ = std::fs::remove_file(OLD_PROCESS);
    });

    println!("awaiting shutdown signal");

    let mut notif_buf = [0; 1];
    socket.set_nonblocking(true).unwrap();

    // 实现类似Mutex::try_read的循环
    while notif_buf[0] == 0 {
        // 执行你的业务工作
        print!(".");
        std::thread::sleep(Duration::MILLISECOND);

        // 尝试读取数据
        match socket.recv(&mut notif_buf) {
            Ok(_) => break, // 读取到数据,退出循环
            Err(e) if e.kind() == io::ErrorKind::WouldBlock => continue, // 无数据,继续工作
            Err(e) => panic!("Failed to receive: {}", e), // 其他致命错误
        }
    }

    println!("\nreceived shutdown signal");
    socket.set_nonblocking(false).unwrap();

    println!("sending data");
    socket.send_to(&[1, 2, 3, 4], NEW_PROCESS).unwrap();
    println!("sent data");
}

fn main() {
    println!("Hello, world!");

    if std::path::Path::new(OLD_PROCESS).exists() {
        println!("non-first");
        startup();
        process();
    } else {
        println!("first");
        process();
    }
}

额外说明

  • 自动清理依赖:需要在Cargo.toml中添加scopeguard = "1.2",这样无论进程正常退出还是panic,./old文件都会被自动删除,不用手动清理。
  • 非阻塞逻辑说明:循环中每次尝试读取,若没有数据就继续执行业务工作;一旦读取到数据就退出循环处理后续流程,完全符合你要的try_read模式。
  • 错误区分:只对WouldBlock做忽略处理,其他IO错误(比如socket损坏)会触发panic,保证程序健壮性。

内容的提问来源于stack exchange,提问作者Jonathan Woollett-light

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 13:40:09