非阻塞Unix数据报读取出现"Resource temporarily unavailable"错误
问题解决与非阻塞读取实现
错误根源
你遇到的WouldBlock错误是非阻塞IO的正常行为:当socket设置为非阻塞模式后,调用recv()时如果没有数据可读,系统会返回这个错误,而你直接用unwrap()把它当成致命错误处理,导致程序panic。
解决方案
核心修改
- 移除
set_read_timeout:非阻塞模式下不需要超时设置,两者混用会导致逻辑混乱。 - 替换
recv().unwrap()为错误匹配逻辑,专门处理WouldBlock,实现你要的try_read式循环。 - 自动清理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
相关产品推荐
相关产品推荐

