如何避免Tokio线程阻塞?Unix域套接字客户端报错排查
问题解决:Tokio UnixStream 出现 WouldBlock 错误崩溃
你的问题出在对try_read的错误处理上:当stream.readable().await返回后,调用try_read仍可能因为没有可用数据(比如内核通知延迟)返回WouldBlock错误,而你直接用?将这个错误抛出,导致程序崩溃。此外,你直接将整个缓冲区写入标准输出,会包含未使用的0字节,导致输出混乱。
修复步骤:
- 显式处理
try_read的返回值,遇到WouldBlock时跳过本次循环,重新等待流可读 - 处理读取到0字节的情况(表示服务器已关闭连接)
- 只写入实际读取到的字节数,并刷新标准输出确保内容立即显示
修改后的完整代码:
use std::env::{var, VarError}; use std::io::{self, Write}; use tokio::net::UnixStream; #[tokio::main] async fn main() -> io::Result<()> { let hypr_instance_sig = match var("HYPRLAND_INSTANCE_SIGNATURE") { Ok(var) => var, Err(VarError::NotPresent) => panic!("Is hyprland running?"), Err(VarError::NotUnicode(_)) => panic!("wtf no unicode?"), }; let socket_path = format!("/tmp/hypr/{hypr_instance_sig}/.socket2.sock"); let stream = UnixStream::connect(socket_path).await?; loop { stream.readable().await?; let mut buf = [0; 4096]; match stream.try_read(&mut buf) { Ok(n) if n == 0 => { // 服务器关闭连接,退出循环 break; } Ok(n) => { // 仅写入实际读取到的字节 io::stdout().lock().write_all(&buf[..n])?; // 刷新输出缓冲,确保内容立即显示 io::stdout().flush()?; } Err(e) if e.kind() == io::ErrorKind::WouldBlock => { // 暂时无数据可读,继续等待下一次readable通知 continue; } Err(e) => { // 其他IO错误,返回错误终止程序 return Err(e); } } } Ok(()) }
额外说明:
readable().await仅保证流曾经处于可读状态,不代表调用try_read时一定能读到数据,所以必须处理WouldBlock- 读取到0字节是TCP/Unix Socket的标准关闭信号,此时应该终止循环
- 同步的
stdout在异步环境中可以使用,但如果追求更好的性能,建议改用tokio::io::AsyncWrite相关的异步输出API
内容的提问来源于stack exchange,提问作者Yavor
相关产品推荐
相关产品推荐

