You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何拆分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和Write trait,因此可以直接传递给zstd的Decoder和Encoder,不需要单独调用reader()或writer()。
  • 若需要真正的并发读写,需将底层的TcpStream拆分为ReadHalf和WriteHalf,并配合Arc<Mutex<ClientConnection>>使用,但rustls的连接模型天生是单线程的,这种方式需要额外注意连接状态的同步。

内容的提问来源于stack exchange,提问作者gucki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 23:14:59