🔥 Muduo + OpenSSL 网络交互完整流程
这套架构结合了 Muduo(网络库)+ OpenSSL(TLS/SSL 加密)+ BIO(缓存),整个数据流动过程如下:
🌍 1. 网络通信的基本流程
Muduo 负责 管理连接和数据传输,但它自己不会加密数据,所以我们引入 OpenSSL 来处理 TLS/SSL 加密。
💡 核心思路:
- 服务器和客户端通过 TCP 连接 进行通信。
- 数据在 发送之前被 SSL 加密,然后交给 Muduo 发送。
- 数据在 接收后先存入 BIO,SSL 再解密,最后交给业务逻辑处理。
🚀 2. 详细的 SSL 网络交互流程
假设你有 A(客户端) 和 B(服务器),它们之间用 TLS/SSL 进行安全通信。
📌(1)客户端连接服务器
- 客户端通过 Muduo 发起 TCP 连接,服务器接受连接。
- 这时候还没开始 SSL/TLS 认证,连接只是普通的 TCP 连接。
📌(2)SSL 握手(TLS/SSL 认证)
👉 目标: 确保数据加密,并建立 SSL 安全通道。
🔹 客户端(A) 发起 SSL 握手
- 客户端 Muduo 建立连接后,初始化 OpenSSL(SSL_new),使用
BIO
进行 I/O 操作。 - 通过
SSL_connect()
发送 Client Hello,尝试建立 TLS 连接。
🔹 服务器(B) 处理 SSL 握手
- 服务器 Muduo 监听到连接后,初始化 SSL_accept() 进行 TLS 认证。
- 服务器返回 Server Hello,协商 TLS 版本、密钥等信息。
🔸 这一步完成后,A 和 B 之间的通信就会被 TLS/SSL 加密了!
📌(3)客户端发送数据
假设 客户端 A 要发送 "Hello Server"
给 服务器 B,数据流如下:
1️⃣ 应用层调用 SSL_write()
进行加密
SSL_write(ssl_, data, len);
- SSL 负责加密数据,但不会直接发网络数据,而是把加密后的数据放进
writeBio_
。
2️⃣ 从 writeBio_
取出加密数据
int bytes = BIO_read(writeBio_, buf, sizeof(buf));
BIO_read()
从writeBio_
读取加密数据(即 TLS 加密后的数据)。
3️⃣ Muduo 负责真正发送数据
conn_->send(buf, bytes);
- Muduo 通过 socket 发送
buf
,这时候的数据已经是 加密后的,即 TLS 报文。
📌(4)服务器接收数据
服务器 B 监听到新的 TCP 数据,流程如下:
1️⃣ Muduo 通过 conn_->recv(buf, len)
接收数据
- 收到的是加密数据(TLS 报文)。
2️⃣ 写入 readBio_
供 SSL 解密
BIO_write(readBio_, buf, len);
- 这相当于把加密数据喂给 SSL,让它去解密。
3️⃣ 调用 SSL_read()
解密数据
SSL_read(ssl_, buf, len);
- 这一步 SSL 从
readBio_
读取数据并解密,得到"Hello Server"
(明文)。 - 服务器最终收到 解密后的明文数据,可以正常处理业务逻辑。
📌(5)服务器回传数据
服务器 B 也可以按照相同的方式给 客户端 A 发送加密数据,流程类似:
SSL_write()
加密数据BIO_read(writeBio_)
取出加密数据conn_->send(buf, bytes)
通过 Muduo 发送
客户端接收数据后:
conn_->recv(buf, len)
接收 加密数据BIO_write(readBio_, buf, len)
存入 BIOSSL_read()
读取并解密,得到明文
🔍 3. 你代码中的数据流
💡 结合你提供的 SslConnection::send()
代码:
void SslConnection::send(const void* data, size_t len)
{
if (state_ != SSLState::ESTABLISHED) {
LOG_ERROR << "Cannot send data before SSL handshake is complete";
return;
}
int written = SSL_write(ssl_, data, len);
if (written <= 0) {
int err = SSL_get_error(ssl_, written);
LOG_ERROR << "SSL_write failed: " << ERR_error_string(err, nullptr);
return;
}
char buf[4096];
int pending;
while ((pending = BIO_pending(writeBio_)) > 0) {
int bytes = BIO_read(writeBio_, buf,
std::min(pending, static_cast<int>(sizeof(buf))));
if (bytes > 0) {
conn_->send(buf, bytes);
}
}
}
📌 代码解析
1️⃣ SSL_write(ssl_, data, len)
进行 TLS 加密,但不会直接发送。
2️⃣ BIO_read(writeBio_, buf, len)
从 writeBio_
取出加密数据。
3️⃣ conn_->send(buf, bytes)
Muduo 负责真正的网络发送。
👉 这里的 conn_->send()
其实就是 Muduo 发送 TCP 数据的封装,最终会调用 send(fd, buf, len, 0)
。
SSL 与 BIO 读写的详细关系
1. 写数据
🔹 流程:应用层 → SSL 层(加密)→ BIO 层(缓存)→ 网络层
应用程序调用 SSL_write(ssl, 明文数据, 长度)
↓
SSL 进行加密,生成加密后的数据
↓
加密后的数据被放入 BIO(写 BIO)
↓
应用程序调用 BIO_read(writeBio, buf, len)
↓
取出加密数据并发送到网络
示例
SSL_write(ssl_, data, len); // 把明文数据加密并放入 write BIO
int pending = BIO_pending(writeBio_); // 检查加密数据是否可读
BIO_read(writeBio_, buf, pending); // 取出加密数据
conn_->send(buf, pending); // 发送到网络
2. 读数据
🔹 流程:网络层 → BIO 层(缓存)→ SSL 层(解密)→ 应用层
数据从网络收到,存入 BIO(读 BIO)
↓
应用程序调用 SSL_read(ssl, buf, len)
↓
SSL 从 BIO 读取加密数据,并解密
↓
返回解密后的明文数据给应用程序
示例
conn_->recv(buf, len); // 从网络接收数据
BIO_write(readBio_, buf, len); // 把加密数据存入 read BIO
int bytes = SSL_read(ssl_, buf, sizeof(buf)); // 从 read BIO 取出数据并解密
📌 4. 总结
SSL 读写与 BIO 读写是 逻辑上的两层操作,它们之间的关系可以用一个缓冲区的概念来理解。
🚀 发送数据流程
🔹 应用层:调用 SSL_write()
加密数据
🔹 BIO:加密数据存入 writeBio_
🔹 Muduo:BIO_read(writeBio_)
取出数据,conn_->send()
发送
📩 接收数据流程
🔹 Muduo:conn_->recv()
接收加密数据
🔹 BIO:BIO_write(readBio_, buf, len)
写入 解密 BIO
🔹 应用层:调用 SSL_read()
取出明文数据
- SSL 不能直接读写 socket,必须通过 BIO 进行数据传输
- SSL 读写操作的目标是 BIO,而 BIO 负责最终的网络 IO
- BIO 作为缓冲区存放加密/解密数据,SSL 只负责加密解密
- 应用程序只操作
SSL_read
和SSL_write
,但实际上 BIO 处理数据的存取
对比理解
操作 | 方向 | 作用 |
---|---|---|
SSL_write(ssl, 明文, 长度) | 应用层 → BIO | 明文 → 加密数据放入 BIO |
BIO_read(writeBio, buf, len) | BIO → 网络 | 读取加密数据,发送 |
BIO_write(readBio, buf, len) | 网络 → BIO | 接收加密数据,存入 BIO |
SSL_read(ssl, buf, len) | BIO → 应用层 | BIO 取出加密数据 → 解密成明文 |
所以,BIO 是 SSL 和实际网络传输之间的桥梁,SSL 处理的是加密/解密,BIO 处理的是数据存取和流转。
🔹 5. 你的架构的优势
✔ 异步非阻塞
- Muduo 负责网络收发,BIO 作为缓存,不会阻塞线程。
✔ 高效解耦 - SSL 只管加密/解密,Muduo 只管传输,彼此解耦,灵活性高。
✔ 可以适配其他 I/O - 你的代码 可以适配不同的传输方式,比如 TCP、UDP,甚至文件存储。
🎯 6. 结论
代码里,SSL 只负责加密,BIO 作为缓存,Muduo 负责真正的传输。
整个流程设计合理,兼顾了 安全性 和 高效性!🚀