SslConnection::SslConnection()详解

news2025/3/5 0:54:55

一、🔍 SslConnection::SslConnection() 详解

这个构造函数的主要作用是:

  1. 创建 SSL 对象
  2. 创建 BIO(I/O 缓冲区)
  3. 初始化 SSL 服务器模式
  4. 绑定回调函数(onRead() 处理接收数据)

📌 1. 初始化 SSL 相关对象

SslConnection::SslConnection(const TcpConnectionPtr& conn, SslContext* ctx)
    : ssl_(nullptr)  // SSL对象(加密/解密)
    , ctx_(ctx)  // SSL 上下文
    , conn_(conn)  // Muduo 连接对象(底层网络传输)
    , state_(SSLState::HANDSHAKE)  // 初始状态:TLS 握手
    , readBio_(nullptr)  // 读 BIO(接收加密数据)
    , writeBio_(nullptr)  // 写 BIO(存储加密数据)
    , messageCallback_(nullptr)  // 业务逻辑的回调(不一定用得上)

💡 这里主要是初始化了一些成员变量,确保构造对象时数据是干净的。


📌 2. 创建 SSL 上下文

ssl_ = SSL_new(ctx_->getNativeHandle());
if (!ssl_) {
    LOG_ERROR << "Failed to create SSL object: " << ERR_error_string(ERR_get_error(), nullptr);
    return;
}

📍 作用

  • 通过 SSL_new(ctx_->getNativeHandle()) 创建 SSL 对象,用于加解密。
  • 如果失败,打印日志并返回。

🔹 ctx_->getNativeHandle() 是什么?

  • 这里的 ctx_SslContext*,表示 SSL 的全局上下文。
  • ctx_->getNativeHandle() 返回的是 OpenSSL 的 SSL_CTX*,它管理 证书、加密方式、TLS 版本等
  • SSL_new() 基于 SSL_CTX* 创建一个 新的 SSL 会话对象,用于该 TCP 连接的数据加解密。

📌 3. 创建 BIO(I/O 缓冲区)

readBio_ = BIO_new(BIO_s_mem());
writeBio_ = BIO_new(BIO_s_mem());

if (!readBio_ || !writeBio_) {
    LOG_ERROR << "Failed to create BIO objects";
    SSL_free(ssl_);
    ssl_ = nullptr;
    return;
}

📍 作用

  • readBio_ = BIO_new(BIO_s_mem()):创建 读 BIO,用于存放接收的加密数据(网络数据)。
  • writeBio_ = BIO_new(BIO_s_mem()):创建 写 BIO,用于存放加密后的待发送数据
  • 这里使用 BIO_s_mem(),表示创建的是 内存 BIO(不会自动关联 socket,手动读写)。
  • 如果创建 BIO 失败,则释放 SSL 资源,防止内存泄露。

📌 4. 绑定 SSL 和 BIO

SSL_set_bio(ssl_, readBio_, writeBio_);

📍 作用

  • 让 OpenSSL 通过 BIO 读写数据,而不是直接操作 socket。
  • readBio_ 存放接收到的加密数据(模拟 OpenSSL 的 SSL_read())。
  • writeBio_ 存放加密后的待发送数据(模拟 SSL_write())。
  • SSL_set_bio() 绑定 BIO 后,SSL_read() 会自动从 readBio_ 读取数据,SSL_write() 会把加密数据存入 writeBio_

💡 这样就实现了 OpenSSL 和 Muduo 的解耦:

  • Muduo 只管传输数据(读写 readBio_writeBio_)。
  • SSL 只管加密/解密(不直接接触网络)。

📌 5. 设置服务器模式

SSL_set_accept_state(ssl_);  // 设置为服务器模式

📍 作用

  • 服务器模式:在 TLS 握手时,服务器等待客户端发起 Client Hello
  • 服务器通过 SSL_accept() 进行 TLS 握手,成功后才能进行加密通信。

📌 6. 设置 SSL 选项

SSL_set_mode(ssl_, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE);

📍 作用

🔹 SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER

  • 允许 SSL_write() 使用动态内存,不要求数据缓冲区保持固定位置(适用于异步网络)。

🔹 SSL_MODE_ENABLE_PARTIAL_WRITE

  • 允许 SSL_write() 部分写入,在数据较长时,不会阻塞,而是先写入部分数据,后续继续发送。

📌 7. 绑定数据接收回调

conn_->setMessageCallback(
    std::bind(&SslConnection::onRead, this, std::placeholders::_1,
             std::placeholders::_2, std::placeholders::_3));

📍 作用

  • conn_ 是 Muduo 的 TCP 连接,它接收加密数据后,会调用 onRead() 处理。
  • onRead() 主要作用:
    1. 先把 加密数据 写入 readBio_
    2. 调用 SSL_read() 解密数据
    3. 解密后的数据交给业务逻辑处理。

🎯 8. 总结

🚀 整个 SslConnection 的构造逻辑可以总结如下:

  1. 创建 SSL 对象(用于加密/解密)。
  2. 创建 BIOreadBio_ 存接收数据,writeBio_ 存待发送数据)。
  3. 绑定 BIO(让 SSL_read() / SSL_write() 读写 BIO)。
  4. 设置 SSL 服务器模式SSL_set_accept_state())。
  5. 设置 SSL 选项(允许 SSL_write() 使用动态内存、支持部分写入)。
  6. 绑定 onRead() 回调,处理 Muduo 网络层的数据。

💡 9. 你的代码和 Muduo/SSL 之间的关系

  • Muduo 负责底层的 TCP 连接和数据收发
  • SSL 负责 TLS/SSL 加解密,但不直接读写 socket,而是通过 BIO 缓冲区进行数据交互。
  • Muduo 只管传输,SSL 只管加解密,BIO 作为中间桥梁

🚀 这套架构解耦了网络层和加密层,这样可以:

  1. 更灵活:BIO 让 SSL 适配不同的 I/O(可以换成文件、内存等)。
  2. 更高效:Muduo 依旧是 非阻塞 IO,BIO 负责数据缓存,不阻塞线程。
  3. 更安全:SSL 加密的数据 Muduo 无法直接解读,避免安全漏洞。

🛠 10. 你可以改进的地方

异常处理更全面

  • 目前如果 SSL_new() 失败,只是打印日志并 return,可以抛出异常或者返回错误码,更容易排查问题。

考虑 BIO_set_mem_eof_return()

  • BIO_s_mem() 可能会在 BIO_read() 读取完数据后返回 0,导致 SSL_read() 误以为连接断开。可以用:
    BIO_set_mem_eof_return(readBio_, -1);
    BIO_set_mem_eof_return(writeBio_, -1);
    
    这样 SSL_read() 还能继续读取新数据。

这部分代码设计得 很合理,核心逻辑非常清晰,已经符合 高性能、可扩展、解耦的要求!🚀

二、为什么使用BIO_s_mem()

OpenSSL 里 BIO(Basic I/O) 有多种类型,而 BIO_s_mem() 只是其中之一。
你可以理解 BIO 就是 OpenSSL 里数据的输入/输出缓冲区,不同类型的 BIO 代表不同的 I/O 方式。


📌 1. OpenSSL 里的 BIO 类型

OpenSSL 提供了 三种主要 BIO,分别是:

BIO 类型描述适用于
BIO_s_socket()直接操作 socket 读写阻塞式网络编程
BIO_s_mem()纯内存缓冲区,需要手动传输数据非阻塞网络、框架
BIO_s_ssl()直接包裹 SSL*,自动处理内部封装更简单

🚀 你这里用了 BIO_s_mem(),它的特点是:

不会自动关联 socket(灵活,可适配任何网络框架)
手动读写数据(Muduo 负责收发,BIO 只是缓存)
适用于事件驱动框架(如 Muduo)


📌 2. BIO_s_mem() 为什么适合 Muduo?

Muduo 是 非阻塞 + 事件驱动 的框架,而 OpenSSL 默认的 SSL_read() / SSL_write() 设计成了 阻塞式,所以直接用 OpenSSL 的 BIO_s_socket() 会导致阻塞整个事件循环,影响服务器性能。

💡 解决方案:使用 BIO_s_mem() 让 Muduo 负责数据收发,OpenSSL 只管加解密。

🌟 BIO_s_mem() 允许这样做:

  1. Muduo 读取 TCP 数据,然后 写入 readBio_
    BIO_write(readBio_, encryptedData, len);
    
  2. OpenSSL 从 readBio_ 里读取数据并解密
    SSL_read(ssl_, decryptedBuffer, len);
    
  3. OpenSSL 处理完数据,调用 SSL_write() 生成加密数据,存入 writeBio_
    SSL_write(ssl_, plaintextData, len);
    
  4. Muduo 负责从 writeBio_ 读取加密数据并发送给客户端
    BIO_read(writeBio_, encryptedBuffer, len);
    sendToClient(encryptedBuffer, len);
    

这样,Muduo 仍然是非阻塞的,BIO 只是一个中间缓冲区,不会影响 Muduo 的事件循环。


📌 3. 其他 BIO 方式为什么不合适?

🚫 BIO_s_socket() 直接绑定 socket

如果你用了 BIO_s_socket(),那么:

  • SSL_read() / SSL_write() 会直接阻塞,导致 Muduo 线程被卡住。
  • 影响服务器性能,不能高并发处理多个连接。

🚫 BIO_s_ssl() 让 OpenSSL 直接处理 I/O

  • 这个 BIO 适用于简单场景,适合自己管理 socket 的程序,比如同步服务器。
  • 但你用的是 Muduo 事件驱动,要自己控制数据流动,所以不适合。

📌 4. 总结

你这里使用 BIO_s_mem() 的原因:

  1. 适配 Muduo 非阻塞模型,不会让 SSL_read() 阻塞线程。
  2. 灵活控制数据流动,BIO 只是缓冲区,Muduo 仍然管理 TCP 读写。
  3. 高性能,避免 OpenSSL 直接操作 socket 导致的效率问题。

🚀 这就是 BIO_s_mem() 在 Muduo 里的最佳应用场景!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2309739.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【计算机网络入门】初学计算机网络(八)

目录 1. S-W协议的信道利用率 2. GBN、SR协议的信道利用率 3.术语补充 3.1 滑动窗口协议 3.2 ARQ协议、连续ARQ协议 4. 信道划分介质访问控制 4.1 时分复用&#xff08;TDM&#xff09; 4.2 统计时分复用&#xff08;STDM&#xff09; 4.3 频分复用&#xff08;FDM&a…

VUE集成Live2d

VUE集成Live2d 目前基于大模型&#xff0c;可以实现一个桌面的3D动画小人&#xff0c;个人猜测可以简介这个项目进行实现 1-参考网址 试了很多项目&#xff0c;只有这个项目直观的把问题说清楚了 Live2D Vue3技术应用:https://blog.csdn.net/hh1233321/article/details/1406947…

C++蓝桥杯基础篇(七)

片头 嗨~小伙伴们&#xff0c;大家好&#xff01;今天我们来一起学习蓝桥杯基础篇&#xff08;七&#xff09;&#xff0c;学习相关字符串的知识&#xff0c;准备好了吗&#xff1f;咱们开始咯&#xff01; 一、字符与整数的联系——ASCII码 每个常用字符都对应一个-128~127的…

el-input实现金额输入

需求&#xff1a;想要实现一个输入金额的el-input&#xff0c;限制只能输入数字和一个小数点。失焦数字转千分位&#xff0c;聚焦转为数字&#xff0c;超过最大值&#xff0c;红字提示 效果图 失焦 聚焦 报错效果 // 组件limitDialog <template><el-dialog:visible.s…

双碳战略下的智慧能源实践:安科瑞储能管理系统助力企业绿色转型

在全球碳中和目标加速推进的背景下&#xff0c;中国“十四五”规划明确提出构建以新能源为主体的新型电力系统&#xff0c;储能技术成为支撑能源结构转型的核心要素。安科瑞储能能量管理系统作为企业级智慧能源解决方案的核心载体&#xff0c;凭借其技术创新与场景适配能力&…

《鸢尾花数学大系:从加减乘除到机器学习》开源资源

《鸢尾花数学大系&#xff1a;从加减乘除到机器学习》开源资源 Gitee&#xff1a;https://gitee.com/higkoo/ bilibili&#xff1a;https://space.bilibili.com/513194466 GitHub&#xff1a;https://github.com/Visualize-ML

本地部署HDFS集群

首先完成本地部署大数据集群前置准备&#xff0c;可参考&#xff1a; 本地部署大数据集群前置准备https://blog.csdn.net/m0_73641796/article/details/145994787?spm1001.2014.3001.5501 1.下载hadoop 下载Hadoop安装包&#xff0c;本文用的是hadoop-3.3.4.tar.gz 2. 集群…

10.【线性代数】—— 四个基本子空间

十、 四个基本子空间 1. 列空间 C ( A ) C(A) C(A) in R m R^m Rm2. 零空间 N ( A ) N(A) N(A) in R n R^n Rn3. 行空间 C ( A T ) C(A^T) C(AT) in R n R^n Rn4. 左零空间 N ( A T ) N(A^T) N(AT) in R m R^m Rm综述5. 新的向量空间 讨论矩阵 A m ∗ n A_{m*n} Am∗n​…

基于vue框架的游戏商城系统cq070(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,分类,商品信息,游戏高手,游戏代练 开题报告内容 基于Vue框架的游戏商城系统开题报告 一、研究背景与意义 随着互联网技术的飞速发展和游戏产业的蓬勃兴起&#xff0c;游戏商城作为游戏产业链中的重要一环&#xff0c;迎来了前所…

我代表中国受邀在亚马逊云科技全球云计算大会re:Invent中技术演讲

大家好我是小李哥&#xff0c;本名叫李少奕&#xff0c;目前在一家金融行业公司担任首席云计算工程师。去年5月很荣幸在全球千万名开发者中被选为了全球亚马逊云科技认证技术专家&#xff08;AWS Hero&#xff09;&#xff0c;是近10年来大陆地区仅有的第9名大陆专家。同时作为…

css3d放置的面板方向不对问题排查

以往在threejs左手坐标系下&#xff0c;cameranew THREE.Vector3(0, 0, 1)&#xff0c;好像在贴css3d的时候从来不会出问题。而这次接到一个朋友是用右手坐标系的&#xff0c;camera默认不设置方向&#xff0c;则应该是&#xff08;0&#xff0c;1&#xff0c;0&#xff09; c…

网络安全法与等级保护 PPT 精华汇总

资源描述 本资源文件为《网络安全法与等级保护》的PPT精华汇总&#xff0c;内容涵盖了网络安全法与等级保护的总体框架及相关标准规范。该PPT详细介绍了网络安全法与等级保护的各个章节和条款&#xff0c;并提供了基础类和应用类的相关标准文件&#xff0c;帮助读者全面了解和…

探秘基带算法:从原理到5G时代的通信变革【十】基带算法应用与对比

文章目录 三、算法在现代通信系统中的应用3.1 5G 通信中的应用3.1.1 信道编码与调制解调3.1.2 大规模 MIMO 技术3.1.3 案例分析&#xff1a;5G 基站与终端实现 3.2 卫星通信中的应用3.2.1 抗干扰与纠错编码3.2.2 信号处理与调制解调3.2.3 案例分析&#xff1a;卫星通信系统实例…

io学习----->标准io

思维导图&#xff1a; 一.io的作用 io是实现对文件的操作&#xff0c;把运行结果存到文件中&#xff0c;读取文件的数据&#xff0c;方便后期查询。 二.io的概念 io是指系统 和外部设备或用户之间的数据交互 I:input 表示数据从外部设备输入到内存中&#xff1b; O:output…

LeetCode 面试题 17.19. 消失的两个数字

LeetCode 面试题 17.19. 消失的两个数字 思路&#x1f9d0;&#xff1a; 运用位运算&#xff0c;我们先创建一个变量tmp&#xff0c;依次异或nums和1~N所有整数&#xff0c;此时就可以得到两个数的异或值。 然后通过右移操作&#xff0c;逐位检查tmp中的每一位&#xff0c;找到…

KaiwuDB| Google Spanner 经典架构回顾

前言 大数据时代 &#xff0c;随着移动互联网和物联网技术的发展 &#xff0c; 全球数据量呈现爆发式增长&#xff0c;已经远远超出集中式单机数据库的处理能力。CCF 数据库专委 2021 年发布的《“十四五”数据库发展趋势与挑战》显示&#xff0c; 各行各业海量数据的管理需求…

拼电商客户管理系统

内容来自&#xff1a;尚硅谷 难度&#xff1a;easy 目 标 l 模拟实现一个基于文本界面的 《 拼电商客户管理系统 》 l 进一步掌握编程技巧和调试技巧&#xff0c;熟悉面向对象编程 l 主要涉及以下知识点&#xff1a; 类结构的使用&#xff1a;属性、方法及构造器 对象的创建与…

项目准备(flask+pyhon+MachineLearning)- 1

目录 这是一篇学习笔记 1. 搭建项目 2.前期准备工作 3.创建用户(user)模板 这是一篇学习笔记 目的&#xff1a;用flask快速实现发布有关机器学习的项目&#xff0c;掌握flask框架&#xff0c;机器学习模型的存储和调用。 1. 搭建项目 使用pycharm创建项目&#xff0c;fl…

1.2.2 使用Maven方式构建Spring Boot项目

本次实战通过Maven方式构建了一个Spring Boot项目&#xff0c;实现了简单的Web应用。首先&#xff0c;创建了Maven项目并设置好项目名称、位置、构建系统和JDK等。接着&#xff0c;添加了Spring Boot的父项目依赖和web、thymeleaf起步依赖。然后&#xff0c;创建了项目启动类He…

C++中函数的调用

************* C topic&#xff1a;call functions ************* 1、为什么要用函数 In every codes, functions are the crucial parts. There are many advantages of the functions. But I introduce two of them. The first usage of the functions is reuse. And th…