Rust网络编程超时控制库timeout-readwrite的使用,实现读写操作的精确超时管理
Rust网络编程超时控制库timeout-readwrite的使用,实现读写操作的精确超时管理
timeout-readwrite是一个Rust库,提供了带超时功能的Reader和Writer结构体。
为什么需要这个库?
当我们使用异步I/O时,有时需要与后台子进程交互。例如,子进程等待某个事件发生并在发生时输出消息到标准输出。我们希望程序能阻塞等待子进程的输出,但如果子进程挂起,程序将永远阻塞。使用TimeoutReader可以设置读取超时,在超时后返回错误。
示例代码
基础示例(无超时控制)
use std::io::{BufRead, BufReader};
use std::io::Result;
use std::process;
fn each_line<R: BufRead>(rdr: R) -> Result<()> {
let lines = rdr.lines();
for rslt_line in lines {
let line = rslt_line?;
println!("{}", line);
}
Ok(())
}
fn do_command(cmd: &str) -> Result<()> {
let mut cmd = process::Command::new(cmd);
let child = cmd.stdout(process::Stdio::piped())
.stderr(process::Stdio::null())
.spawn().expect("spawning did not succeed");
let stdout = child.stdout?;
each_line(BufReader::new(stdout))
}
使用TimeoutReader添加超时控制
use std::time::Duration;
fn do_command(cmd: &str) -> Result<()> {
let mut cmd = process::Command::new(cmd);
let child = cmd.stdout(process::Stdio::piped())
.stderr(process::Stdio::null())
.spawn().expect("spawning did not succeed");
let stdout = child.stdout?;
each_line(BufReader::new(TimeoutReader::new(stdout, Duration::new(5, 0))))
}
完整示例
use std::io::{BufRead, BufReader, Result};
use std::process;
use std::time::Duration;
use timeout_readwrite::TimeoutReader;
// 处理每一行输出的函数
fn each_line<R: BufRead>(rdr: R) -> Result<()> {
let lines = rdr.lines();
for rslt_line in lines {
match rslt_line {
Ok(line) => println!("{}", line),
Err(e) => {
eprintln!("读取错误: {}", e);
break;
}
}
}
Ok(())
}
// 执行命令并设置读取超时
fn do_command_with_timeout(cmd: &str) -> Result<()> {
// 创建子进程
let mut cmd = process::Command::new(cmd);
let child = cmd.stdout(process::Stdio::piped())
.stderr(process::Stdio::null())
.spawn()
.expect("启动子进程失败");
// 获取子进程的标准输出
let stdout = child.stdout?;
// 创建带5秒超时的TimeoutReader
let timeout_reader = TimeoutReader::new(stdout, Duration::new(5, 0));
// 使用带缓冲的读取器处理输出
each_line(BufReader::new(timeout_reader))
}
fn main() {
if let Err(e) = do_command_with_timeout("your_command") {
eprintln!("命令执行错误: {}", e);
}
}
使用方法
- 在Cargo.toml中添加依赖:
[dependencies]
timeout-readwrite = "0.4.0"
- 在代码中使用:
extern crate timeout_readwrite;
use timeout_readwrite::TimeoutReader;
use std::time::Duration;
工作原理
TimeoutReader包装了现有的Reader,在每次读取操作时检查是否超过指定的超时时间。如果超过超时时间,读取操作将返回ErrorKind::TimeOut
错误。
现在,如果程序等待子进程输出的时间超过5秒而没有收到数据,读取操作将失败并返回超时错误,而不是无限期阻塞。
1 回复
Rust网络编程超时控制库timeout-readwrite使用指南
timeout-readwrite
是一个专门为Rust网络编程设计的库,它提供了精确的读写操作超时控制功能,帮助开发者避免网络I/O操作无限期阻塞的问题。
主要特性
- 为
Read
和Write
trait提供超时包装 - 精确到毫秒级别的超时控制
- 支持标准库和Tokio异步运行时
- 简单易用的API设计
安装方法
在Cargo.toml
中添加依赖:
[dependencies]
timeout-readwrite = "0.3"
基本使用方法
同步I/O超时控制
use std::net::TcpStream;
use std::time::Duration;
use timeout-readwrite::TimeoutReader;
fn main() -> std::io::Result<()> {
let stream = TcpStream::connect("example.com:80")?;
let mut reader = TimeoutReader::new(stream, Duration::from_secs(5));
let mut buf = [0; 1024];
match reader.read(&mut buf) {
Ok(n) => println!("Read {} bytes", n),
Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {
println!("Read operation timed out");
}
Err(e) => return Err(e),
}
Ok(())
}
异步I/O超时控制(Tokio)
use tokio::net::TcpStream;
use std::time::Duration;
use timeout-readwrite::TimeoutReaderExt;
#[tokio::main]
async fn main() -> std::io::Result<()> {
let stream = TcpStream::connect("example.com:80").await?;
let mut reader = stream.timeout_reader(Duration::from_secs(5));
let mut buf = [0; 1024];
match reader.read(&mut buf).await {
Ok(n) => println!("Read {} bytes", n),
Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {
println!("Read operation timed out");
}
Err(e) => return Err(e),
}
Ok(())
}
高级用法
读写分别设置不同超时
use std::net::TcpStream;
use std::time::Duration;
use timeout-readwrite::{TimeoutReader, TimeoutWriter};
fn main() -> std::io::Result<()> {
let stream = TcpStream::connect("example.com:80")?;
// 读超时5秒,写超时10秒
let mut reader = TimeoutReader::new(stream.try_clone()?, Duration::from_secs(5));
let mut writer = TimeoutWriter::new(stream, Duration::from_secs(10));
// 读取数据
let mut buf = [0; 1024];
reader.read(&mut buf)?;
// 写入数据
writer.write_all(b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")?;
Ok(())
}
动态调整超时时间
use std::net::TcpStream;
use std::time::Duration;
use timeout-readwrite::TimeoutReader;
fn main() -> std::io::Result<()> {
let stream = TcpStream::connect("example.com:80")?;
let mut reader = TimeoutReader::new(stream, Duration::from_secs(5));
// 初始读取使用5秒超时
let mut buf = [0; 1024];
reader.read(&mut buf)?;
// 后续读取调整为2秒超时
reader.set_timeout(Duration::from_secs(2));
reader.read(&mut buf)?;
Ok(())
}
完整示例
下面是一个完整的HTTP客户端示例,演示如何使用timeout-readwrite库进行网络请求:
use std::net::TcpStream;
use std::time::Duration;
use std::io::{Read, Write};
use timeout_readwrite::{TimeoutReader, TimeoutWriter};
fn main() -> std::io::Result<()> {
// 建立TCP连接
let stream = TcpStream::connect("example.com:80")?;
// 设置读写超时
let mut reader = TimeoutReader::new(stream.try_clone()?, Duration::from_secs(5));
let mut writer = TimeoutWriter::new(stream, Duration::from_secs(3));
// 发送HTTP请求
writer.write_all(b"GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n")?;
// 读取响应
let mut response = Vec::new();
let mut buf = [0; 1024];
loop {
match reader.read(&mut buf) {
Ok(0) => break, // 连接关闭
Ok(n) => response.extend_from_slice(&buf[..n]),
Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {
println!("读取超时,已读取部分响应");
break;
}
Err(e) => return Err(e),
}
}
// 打印响应
println!("{}", String::from_utf8_lossy(&response));
Ok(())
}
注意事项
- 超时错误会被包装为
std::io::ErrorKind::TimedOut
类型的错误 - 对于异步操作,超时是通过Tokio的计时器实现的
- 超时精度取决于系统计时器的精度
- 频繁设置很短的超时时间可能会影响性能
timeout-readwrite
库为Rust网络编程提供了简单可靠的超时控制机制,是构建健壮网络应用的实用工具。