<<一种 Windows IOCP 整合 OpenSSL 实现方案>>

by 阙荣文 Que's C++ Studio
2021-06-06

TedQue/IOCP_SSL_Demo: IOCP integrate with OpenSSL (github.com)

1. IOCP 和 epoll 编程模型比较

本来程序员们都已经习惯了传统的 select 模型(包括 linux epoll 和 BSD kqueue),非常好理解. 但 Windows IOCP API接口另搞了一套,显得相当异类.
我个人还是更喜欢传统的 select 模型,而且我认为所谓的重叠操作没什么意义,为什么需要同时投递多个同类请求呢?比如发送一个大文件时,我们不可能放任程序一直投递写请求而使内存用量失控.
基于上述原因,也为了跨平台使用方便,最终把 IOCP 封装为 epoll 风格的接口,程序结构大致如下,是最常见的事件循环:

for (;;)
    {
        // 等待网络事件
        selector->wait(&socket, &ev);
        
        // 分类处理活跃的网络事件
        if (TEST_BIT(ev, IO_EVENT_SEND))
        {
        }
        else if (TEST_BIT(ev, IO_EVENT_RECV))
        {
        }
        else
        {
        }
    }
    详情请参考 main() 函数.

2. 理解 OpenSSL API 的抽象结构

作为 OpenSSL 库用户,我们可以把它理解为一个黑盒,加密时写入明文读出密文,解密时写入密文读出明文.这个黑盒的操作接口被称为 "BIO",也就是说 SSL 库通过 BIO 接口与外界交互信息,
而 socket 只是众多 BIO 实现之一.利用 BIO 接口,可以把 SSL 协议应用到任意类型的数据通道中,这就是抽象的威力.
通信连接建立之后,通信双方还需要进行 SSL 握手,握手过程中也会产生数据交互,在同步套接字中,调用 SSL_accept() 或者 SSL_connect() 会阻塞直到握手完成;
在异步套接字中则需要反复调用 SSL_do_handshake() 直到返回 1 为止.
由于 SSL 协议中通信双方并非对等,而分为服务器端和客户端两个不同角色,所以在调用 SSL_do_handsake() 之前,
我们需要调用 SSL_set_accept_state() 把 SSL 设置为服务器端角色或者 SSL_set_connect_state()设置为客户端角色.
对于 SSL 握手协议而言 SSL_accept() = SSL_set_accept_state() + SSL_do_handsake(); SSL_connect() = SSL_set_connect_state() + SSL_do_handsake().

3. IOCP 与 OpenSSL 整合思路

通过对上述 BIO 接口的介绍可知, BIO 接口是整合 IOCP 与 OpenSSL 最符合设计原则的方案.
OpenSSL 库中提供了众多 BIO 实现,其中内存 bio_mem 似乎很符合我们的需要,思路是通过 SSL_write() 把密文写入 bio_mem, 然后 IOCP 工作线程从该 bio_mem 中读取密文并发送出去;
接收时, IOCP 工作线程把密文写入 bio_mem,再调用 SSL_read() 读取该 bio_mem 得到明文.这个方案毫无疑问是可行的.但是也有不足之处,数据先写入 bio_mem 再写入 IOCP 缓冲区,需要
两倍缓冲区占用和内存复制,此其一; 在通常使用异步套接字的习惯中,我们总是一直调用 SSL_write() 直到返回 -1 为止,bio_mem 会自动扩展内存用量,所以只要内存足够,我们可以一直调用 
SSL_write() 把所有数据全部写入内存,为了避免出现这种情况,只好修改调用 SSL_write() 惯用法,此其二.
另一个方案是实现自己的 BIO,使 SSL_read/write() 直接读写 IOCP 缓冲区,使 BIO 完全按照我们的期望运行.参考 bio_mem 的实现源码 crypto/bio/bss_mem.c 并不难做到, demo 中采用
的就是这个方案.在编写此 demo 的过程中还有个小插曲,这个 demo 的主要代码写于 2016 年,近日安装了最新版 OpenSSL 后发现编译不通过了,原来是新版库已经不再暴露 BIO_METHOD 结构,需要调用
一组 BIO_meth_xxx() 接口访问该结构.这当然是正确的,作为用户最好只使用接口而不要过多介入内部细节.

实现可供 SSL_read/write() 使用的 BIO 需要以下3个关键函数,分别对应 BIO_read(), BIO_write() 和 BIO_flush() 在此3个函数中我们让 SSL 库直接读写 IOCP 缓冲区.
详情请参考源码 IoSocketSSLImpl.cpp 之 bio_iocp_read(), bio_iocp_write() 和 bio_iocp_ctrl().

[后记]
早就想写点关于 IOCP 和 OpenSSL 整合的文章,但 IOCP 模型一般用在大项目中不是很好剥离,一拖数年直到现在才完成,惭愧.
这个 demo 是从本人的另一个项目中抽取出来的,为了减少干扰简化了诸如超时控制,多线程安全等相关代码,也没有经过仔细测试,主要演示上述整合方案的可行性,望见谅.

================================================================
附1: 本项目访问 https://www.baidu.com/ 的效果(证书信息输出在下方的调试器窗口中)
screenshot.png

附2: 我在本机 Windows 10 上编译安装 OpenSSL 说明(如果您无法编译 demo 请对比此安装流程)
1. 安装 Visual Studio 2019 社区版
2. 下载 OpenSSL 源码 https://github.com/openssl/openssl ,按照 NOTES-WINDOWS.md 文件说明按部就班操作.
3. 安装 Perl http://strawberryperl.com/ 并添加安装路径到 path 环境变量,运行命令 "perl --version" 可正确打印版本信息.
4. 安装 nasm https://www.nasm.us 并添加安装路径到 path 环境变量,运行命令 "nasm --version" 可正确打印版本信息.
5. 编译 32 位 OpenSSL 库
    以管理员权限从开始菜单启动 "Developer Command Prompt for VS 2019" 之后 cd 至 OpenSSL 源码目录
    运行命令 "perl Configure VS-WIN32" 配置 OpenSSL 生成选项为 VS-WIN32
    运行命令 "nmake"
    运行命令 "nmake test"
    运行命令 "nmake install" (默认安装路径在 C:\Program Files (x86)\OpenSSL)
6. 把上述 OpenSSL 安装路径添加至 path 环境变量中,运行命令 "openssl version" 可正确打印版本信息.
7. 在 VS 项目中引用 OpenSSL
    添加 C:\Program Files (x86)\OpenSSL\include 到 Visual Studio 项目的包含目录
    添加 C:\Program Files (x86)\OpenSSL\lib 到 Visual Studio 项目的库目录
    引入库 libcrypto.lib, libssl.lib 依赖

一种 Windows IOCP 整合 OpenSSL 实现方案相关推荐

  1. Windows下配置OpenSSL(傻瓜式教程,一看就会)

    作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 OpenSSL是什么? SSL是Secure Sockets Layer(安全套接层协议)的缩写 ...

  2. 五种windows密码设置及破解(转)

    在使用电脑的过程中,难免要与各类密码打交道,以下九种密码可能是大家用的最多的:BIOS密码.安装密码.用户密码.电源管理密码.屏保密码.开机密码.上网密码.分级审查密码和共享密码.今天,我们就谈谈这些 ...

  3. 在c#使用Windows IOCP(完成端口)编程研究

    一:概述 (1)IOCP是什么呢? 它就是Io   Completion   Port的缩写,它就是MS的内核调用机制.    因为在硬件里,与驱动程序打交道都是通过协议栈进行的,并且是通过发送包请求 ...

  4. AI中台:一种敏捷的智能业务支持方案|宜信技术学院沙龙分享实录

    内容来源:宜信技术学院第1期技术沙龙-线上直播|AI中台:一种敏捷的智能业务支持方案 主讲人介绍:井玉欣 宜信技术研发中心AI应用团队负责人 本文字数:13479字 阅读用时:34分钟 导读:随着&q ...

  5. 一种基于OpenCV的三维重建实现方案

    一种基于OpenCV的三维重建实现方案 来源:淘金者论文范文 作者:Www.TaoJz.Com 日期:08/30/09 摘 要 本文以计算机视觉三维重建技术为研究对象,分析了开放计算机视觉函数库Ope ...

  6. 微信windows版_Windows也可以安逸的无缝同步文件--从Mac OS 转战到Windows后的文件同步方案...

    因为工作原因由原来的MacBook pro更换为到surface book乞丐版(原因为mac下的AutoCAD太难用,autodesk你们就不能学学adobe公司吗?ps相当顺滑可惜我用不到),然而 ...

  7. 硬盘克隆带linux系统,一种Windows环境下基于DiskGenius克隆Linux系统的方法及系统与流程...

    本发明涉及服务器操作系统技术领域,特别是一种windows环境下基于diskgenius克隆linux系统的方法及系统. 背景技术: 服务器在测试过程中需要反复安装linux操作系统用于服务器的各种测 ...

  8. 从数据中台到AI中台:一种敏捷的智能业务支持方案( 附视频讲解) | 技术头条...

    点击上方↑↑↑蓝字关注我们~ 「2019 Python开发者日」全日程揭晓,请扫码咨询 ↑↑↑ 来源 | 宜信技术学院第1期技术沙龙-线上直播 原标题为:AI中台:一种敏捷的智能业务支持方案 导读:随 ...

  9. Windows平台安装OpenSSL

    Windows平台安装openssl有两种方法,第一种是直接下载安装包进行安装.第二种是下载源站进行编译安装 1.直接下载安装包进行安装(最简单) 1.1 下载安装包 Window 的openssl的 ...

最新文章

  1. r语言将百分数化为小数_如何将数字格式化为R中的百分比?
  2. android 获取指定月份的开始时间 结束时间
  3. eclipse的任务列表
  4. UVA - 10168 Summation of Four Primes(哥德巴赫猜想)
  5. Pytest入门【1】
  6. Taro+react开发(69):传入localstoage需要jsonstringfy处理
  7. GBT19056精要
  8. JDBC——实现通用的查询
  9. php 收缩栏,HTML5每日一练之details展开收缩标签的应用
  10. linux手机用什么购物支付,商城系统的微信支付应该如何配置?
  11. 数据结构与算法笔记(三) 线性表(链式描述) 链表
  12. 初三学生什么时候上一对一效果最好?
  13. 《嵌入式系统项目分析入门与实践》 读后感(1)
  14. 课堂随机点名神器6个系列原创软件[2]红包雨版随机点名
  15. wow插件补充说明篇
  16. uniapp的uni.compressImage压缩图片的巨坑
  17. 铁流:中国突破半导体新工艺研发
  18. PTA——基础编程题 | 7-27 冒泡法排序 (20分)
  19. J0ker的CISSP之路:What's CISSP
  20. 远场语音交互硬件声学性能测试标准

热门文章

  1. Oracle之Hint使用总结
  2. Android LowmemoryKiller机制
  3. lc0324 lc0325
  4. C Primer Plus(第六版)第六章6.16编程练习-6.16代码
  5. 效率源linux,效率源FAS7900现场勘验取证系统,多项产品功能惊喜来袭!
  6. 技术Leader,技术和管理哪个重要?
  7. 2019趣头条运营方法,趣头条如何获取收益
  8. vs2013无法启动IIS Expres Web服务器
  9. SpringBoot实战之整合WebSocket之群聊
  10. 美团(三)之登录到主页面间的加载界面