使用socket2 crate实现非阻塞TCP Socket连接失败问题排查
Rust socket2非阻塞TCP连接问题
我正在使用socket2 crate将部分代码从阻塞模式转为非阻塞模式,但在连接Socket时遇到问题——Socket总是在超时前连接失败。查找了相关示例,但未找到Rust中创建非阻塞TCP流的代码。
原阻塞代码情况
原阻塞代码运行正常,但为每个Socket创建新线程成本过高:
let address = SocketAddr::from(([x, y, z, v], port)); let mut socket = TcpStream::connect_timeout(&address, timeout)?;
当前非阻塞连接的问题
由于connect_timeout仅支持阻塞模式,我改用connect并定期轮询Socket状态,但调用connect时持续返回WouldBlock错误,不确定该错误含义,也不清楚是否需要绑定地址、是否需重试连接,以及还有哪些错误需要处理:
use std::io::ErrorKind; use socket2::{Domain, Socket, Type, Protocol, SockAddr}; use std::net::SocketAddr; let address = SocketAddr::from(([x, y, z, v], port)); // 创建等价于TcpStream的Socket let socket = Socket::new(Domain::IPV4, Type::STREAM, Some(Protocol::TCP))?; // 启用Socket的非阻塞模式 socket.set_nonblocking(true)?; // 应该期待什么返回?需要先绑定地址吗? match socket.connect(&address.into()) { Ok(_) => {} Err(e) if e.kind() == ErrorKind::WouldBlock => { // 我一直收到这个错误,但不知道它的含义 // 非阻塞连接不可用吗? // 需要持续尝试连接直到成功? }, // 还有哪些类型的错误需要先处理,再判定连接失败? Err(e) => return Err(e), }
连接状态判断的困惑
同时我不确定判断Socket是否连接成功的正确方式。目前我尝试读取零长度缓冲区,通过是否返回NotConnected错误判断,但不清楚此场景下WouldBlock的含义,且从未得到连接成功的结果:
use std::io::ErrorKind; let mut buffer = [0u8; 0]; // 我也试过self.socket.peer_addr(),但遇到过明明未连接却返回成功的情况 match self.socket.read(&mut buffer) { Ok(_) => Ok(true), // 这里的WouldBlock是什么意思? Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(false), Err(e) if e.kind() == ErrorKind::NotConnected => Ok(false), Err(e) => Err(e), }
测试情况
每个Socket会被定期检查直到超时(20秒),但连接已知可用服务器时,所有Socket都未在超时前连接成功。测试在Windows单线程应用中进行,该服务器在阻塞代码中可正常连接。
最小可复现代例
use socket2::{Domain, Socket, Type, Protocol, SockAddr}; use std::io; use std::net::{SocketAddr, TcpStream}; use std::time::{Duration, Instant}; fn main() -> io::Result<()> { let address = SocketAddr::from(([127, 0, 0, 1], 8080)); let timeout = Duration::from_secs(20); let start = Instant::now(); // 非阻塞连接尝试 let socket = Socket::new(Domain::IPV4, Type::STREAM, Some(Protocol::TCP))?; socket.set_nonblocking(true)?; match socket.connect(&address.into()) { Ok(_) => println!("立即连接成功"), Err(e) if e.kind() == io::ErrorKind::WouldBlock => { println!("返回WouldBlock,等待中..."); } Err(e) => return Err(e), } while start.elapsed() < timeout { // 检查是否已连接 let mut buf = [0u8; 0]; match socket.read(&mut buf) { Ok(_) => { println!("连接成功!"); return Ok(()); } Err(e) if e.kind() == io::ErrorKind::WouldBlock => { // 等待片刻后重试 std::thread::sleep(Duration::from_millis(100)); } Err(e) if e.kind() == io::ErrorKind::NotConnected => { // 是否需要重试连接? println!("未连接,重试中..."); match socket.connect(&address.into()) { Ok(_) => { println!("重试后连接成功"); return Ok(()); } Err(e) if e.kind() == io::ErrorKind::WouldBlock => {} Err(e) => return Err(e), } } Err(e) => return Err(e), } } println!("超时"); Ok(()) }
内容的提问来源于stack exchange,提问作者Locke
相关产品推荐
相关产品推荐

