Rust异步运行时兼容库tor-rtcompat的使用,实现跨Tokio和async-std运行时的无缝切换
Rust异步运行时兼容库tor-rtcompat的使用,实现跨Tokio和async-std运行时的无缝切换
概述
Rust对异步编程的支持很强大,但还不够成熟:有多个强大的运行时可供使用,但它们没有暴露一致的接口。
futures
API抽象了这些运行时库之间的许多差异,但仍有一些领域尚未存在标准API,包括:
- 网络编程
- 时间和延迟
- 启动新任务
- 阻塞直到任务完成
此外,futures
提供的AsyncRead
和AsyncWrite
traits与tokio
提供的不同,需要使用兼容性包装器。
使用tor-rtcompat
tor-rtcompat
crate提供了几个封装不同运行时能力的traits:
ToplevelBlockOn
- 运行时可以阻塞在顶级future上SleepProvider
- 运行时可以创建定时器futureCoarseTimeProvider
- 运行时提供单调时钟NetStreamProvider<std::net::SocketAddr>
- 运行时可以建立和接收TCP连接TlsProvider
- 运行时可以建立TLS连接
完整示例代码
首先需要添加依赖到Cargo.toml:
[dependencies]
tor-rtcompat = { version = "0.3", features = ["tokio", "async-std", "native-tls"] }
tokio = { version = "1.0", features = ["full"] }
async-std = "1.0"
然后是一个完整的示例展示如何在不同运行时之间切换:
use tor_rtcompat::{PreferredRuntime, Runtime};
use std::time::Duration;
// 通用的异步函数,可在任何Runtime下运行
async fn common_async_task(runtime: impl Runtime) {
println!("Starting async task...");
// 使用运行时提供的sleep功能
runtime.sleep(Duration::from_secs(1)).await;
println!("Task completed after 1 second");
}
// 使用Tokio运行时
#[tokio::main]
async fn tokio_example() {
let runtime = PreferredRuntime::current().unwrap();
common_async_task(runtime).await;
}
// 使用async-std运行时
#[async_std::main]
async fn async_std_example() {
let runtime = PreferredRuntime::current().unwrap();
common_async_task(runtime).await;
}
// 显式创建运行时
fn explicit_runtime_example() {
// 创建Tokio运行时(使用native-tls)
let runtime = tor_rtcompat::tokio::TokioNativeTlsRuntime::create().unwrap();
runtime.block_on(async {
common_async_task(runtime).await;
});
}
// 主函数选择运行不同的示例
fn main() {
// 取消注释想要运行的示例
// tokio_example();
// async_std_example();
explicit_runtime_example();
}
Cargo features配置
在Cargo.toml中配置features:
# 默认使用Tokio + native-tls
tor-rtcompat = { version = "0.3", features = ["tokio", "native-tls"] }
# 或者使用async-std + rustls
tor-rtcompat = { version = "0.3", features = ["async-std", "rustls"] }
# 或者全部启用
tor-rtcompat = { version = "0.3", features = ["tokio", "async-std", "native-tls", "rustls"] }
1 回复
以下是基于您提供的内容整理的tor-rtcompat
完整示例演示:
基础TCP服务器示例(包含运行时选择)
use tor_rtcompat::{Runtime, TcpListener, TcpStream};
use std::io::{self, Write};
// 处理TCP连接的异步函数
async fn handle_connection(mut stream: TcpStream) -> io::Result<()> {
// 模拟处理逻辑
stream.write_all(b"HTTP/1.1 200 OK\r\n\r\nHello from tor-rtcompat!").await?;
Ok(())
}
// 通用的TCP服务器实现
async fn run_server<R: Runtime>(rt: R) -> io::Result<()> {
let listener = rt.listen("127.0.0.1:8080").await?;
println!("Server running on 127.0.0.1:8080");
loop {
let (stream, _) = listener.accept().await?;
rt.spawn(async move {
if let Err(e) = handle_connection(stream).await {
eprintln!("Connection error: {}", e);
}
});
}
}
// 根据选择的运行时启动服务器
fn main() -> io::Result<()> {
// 使用Tokio运行时
#[cfg(feature = "tokio")]
{
use tor_rtcompat::tokio::PreferredRuntime;
let rt = PreferredRuntime::new()?;
rt.block_on(run_server(rt))
}
// 使用async-std运行时
#[cfg(feature = "async-std")]
{
use tor_rtcompat::async_std::PreferredRuntime;
let rt = PreferredRuntime::new()?;
rt.block_on(run_server(rt))
}
}
定时器与TCP客户端示例
use tor_rtcompat::{Runtime, Sleep, TcpStream};
use std::time::Duration;
// 带超时的TCP客户端
async fn fetch_with_timeout<R: Runtime>(rt: R) -> io::Result<()> {
// 设置1秒超时
let sleep = Sleep::new(&rt, Duration::from_secs(1));
// 尝试连接
let connect_fut = TcpStream::connect(&rt, "example.com:80");
tokio::select! {
_ = sleep => {
eprintln!("Connection timed out");
Err(io::Error::new(io::ErrorKind::TimedOut, "Connection timeout"))
}
res = connect_fut => {
let mut stream = res?;
println!("Connected successfully!");
// 这里可以添加实际的请求逻辑
Ok(())
}
}
}
// 运行时特征检测示例
fn check_runtime<R: Runtime>(rt: &R) {
println!("Runtime supports I/O: {}", rt.supports_io());
println!("Runtime supports time: {}", rt.supports_time());
}
Cargo.toml配置示例
[package]
name = "tor-rtcompat-demo"
version = "0.1.0"
edition = "2021"
# 选择其中一个运行时特性
[dependencies]
tor-rtcompat = { version = "0.3", features = ["tokio"] }
# 或者
# tor-rtcompat = { version = "0.3", features = ["async-std"] }
# 根据选择的运行时添加相应依赖
[features]
default = ["tokio"]
tokio = ["tor-rtcompat/tokio"]
async-std = ["tor-rtcompat/async-std"]
自定义运行时适配器示例
use tor_rtcompat::{Runtime, Sleep, TcpListener, TcpStream};
use std::time::Duration;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
struct DummyRuntime;
impl Runtime for DummyRuntime {
fn sleep(&self, duration: Duration) -> Sleep {
Sleep::new(self, duration)
}
fn listen(&self, addr: &str) -> Pin<Box<dyn Future<Output = io::Result<TcpListener>> + Send + 'static>> {
Box::pin(async move {
Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
})
}
fn spawn(&self, future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>) {
// 简单的spawn实现
tokio::spawn(future);
}
fn supports_io(&self) -> bool { false }
fn supports_time(&self) -> bool { true }
}
测试建议
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "tokio")]
#[tokio::test]
async fn test_with_tokio() {
let rt = tor_rtcompat::tokio::PreferredRuntime::new().unwrap();
// 测试代码...
}
#[cfg(feature = "async-std")]
#[async_std::test]
async fn test_with_async_std() {
let rt = tor_rtcompat::async_std::PreferredRuntime::new().unwrap();
// 测试代码...
}
}
这些示例展示了tor-rtcompat
的核心用法,包括:
- 基础TCP服务器实现
- 运行时无关的异步操作
- 跨运行时的定时器使用
- 自定义运行时适配器
- 多运行时测试方案
实际使用时,请根据项目需求选择合适的运行时,并在Cargo.toml中配置相应的feature。