如何拆分rustls流为Reader和Writer以实现SSL连接压缩?
为rustls SSL连接添加zstd压缩的可变借用问题解决
我希望使用zstd crate为基于rustls的SSL连接添加压缩功能,但无法找到拆分rustls流为Reader和Writer的方法来构建Encoder和Decoder。另外我需要在Reader上使用read_line方法,因此添加了BufReader。我的代码如下:
let mut conn = rustls::ClientConnection::new(Arc::new(config), server_name).unwrap(); let mut sock = TcpStream::connect("www.rust-lang.org:443").unwrap(); let mut tls = rustls::Stream::new(&mut conn, &mut sock); let mut r = BufReader::new(Decoder::new(tls.conn.reader()).unwrap()); let mut w = Encoder::new(tls.conn.writer(), 0).unwrap();
编译时出现以下错误:
error[E0499]: cannot borrow `*tls.conn` as mutable more than once at a time --> src/main.rs:166:28 | | let mut r = BufReader::new(Decoder::new(tls.conn.reader()).unwrap()); | -------- first mutable borrow occurs here | let mut w = Encoder::new(tls.conn.writer(), 0).unwrap(); | ^^^^^^^^ second mutable borrow occurs here | r.read_to_end(&mut plaintext).unwrap(); | - first borrow later used here
解决方案
这个错误的核心是Rust的借用规则:不能同时对同一个可变值持有多个可变引用。tls.conn.reader()和tls.conn.writer()都会返回对conn的可变引用,因此无法同时创建Decoder和Encoder。
根据使用场景,有两种可行的解决方式:
1. 串行读写(单线程场景推荐)
如果读写操作是串行执行的(先读后写,或先写后读),可以直接复用同一个rustls::Stream,分别在需要时创建Decoder和Encoder:
let mut conn = rustls::ClientConnection::new(Arc::new(config), server_name).unwrap(); let mut sock = TcpStream::connect("www.rust-lang.org:443").unwrap(); let mut tls = rustls::Stream::new(&mut conn, &mut sock); // 读取数据:用zstd解码并包装为BufReader let mut r = BufReader::new(Decoder::new(&mut tls).unwrap()); let mut plaintext = String::new(); r.read_line(&mut plaintext).unwrap(); // 写入数据:用zstd编码 let mut w = Encoder::new(&mut tls, 0).unwrap(); w.write_all(b"your data here").unwrap(); w.finish().unwrap(); // 必须调用finish确保压缩数据全部写入
2. 内部可变性(并发场景)
如果需要同时持有读写句柄(比如多线程并发读写),可以用Arc<Mutex>包装ClientConnection,通过锁来控制对conn的可变访问:
use std::sync::{Arc, Mutex}; let conn = Arc::new(Mutex::new(rustls::ClientConnection::new(Arc::new(config), server_name).unwrap())); let mut sock = TcpStream::connect("www.rust-lang.org:443").unwrap(); // 构建读端 let conn_read = Arc::clone(&conn); let mut r = BufReader::new(Decoder::new(Stream::new(&mut conn_read.lock().unwrap(), &mut sock)).unwrap()); // 构建写端 let conn_write = Arc::clone(&conn); let mut w = Encoder::new(Stream::new(&mut conn_write.lock().unwrap(), &mut sock), 0).unwrap();
注意:使用这种方式时,同一时间只有一个操作能访问conn,读写操作会被串行化。
补充说明
rustls::Stream本身已经实现了Read和Writetrait,因此可以直接传递给zstd的Decoder和Encoder,不需要单独调用reader()或writer()。- 若需要真正的并发读写,需将底层的
TcpStream拆分为ReadHalf和WriteHalf,并配合Arc<Mutex<ClientConnection>>使用,但rustls的连接模型天生是单线程的,这种方式需要额外注意连接状态的同步。
内容的提问来源于stack exchange,提问作者gucki
相关产品推荐
相关产品推荐

