SSL 非阻塞通信方法及用于 SSL 非阻塞通信的服务器 技术领域 本申请涉及网络通信的技术领域, 特别是涉及一种 SSL 非阻塞通信的方法, 以及 一种用于 SSL 非阻塞通信的服务器。
背景技术 SSL(Secure Sockets Layer 安全套接层 ) 是为网络通信提供安全及数据完整性的 一种安全协议, 用以保障在 Internet 上数据传输之安全, 其利用数据加密 (Encryption) 技 术, 可确保数据在网络上之传输过程中不易被截取及窃听。它已被广泛地用于 Web 浏览器 与服务器之间的身份认证和加密数据传输。
SSL 协议位于 TCP/IP 协议与各种应用层协议之间, 为数据通讯提供安全支持。 SSL 协议可分为两层 :
第一层 : SSL 记录协议 (SSL Record Protocol), 它建立在可靠的传输协议 ( 如 TCP) 之上, 为高层协议提供数据封装、 压缩、 加密等基本功能的支持。
第二层 : SSL 握手协议 (SSL Handshake Protocol), 它建立在 SSL 记录协议之上, 用于在实际的数据传输开始前, 通讯双方进行身份认证、 协商加密算法、 交换加密密钥等。
SSL 协议提供的服务主要有 : 1) 认证用户和服务器, 确保数据发送到正确的客户 机和服务器 ; 2) 加密数据以防止数据中途被窃取 ; 3) 维护数据的完整性, 确保数据在传输 过程中不被改变。
目前, 基于 SSL 协议的通信方式主要包括阻塞通信方式和非阻塞通信方式 :
JDK(Java Development Kit) 中的 SSLServerSocket 和 SSLSocket 就提供了 SSL 协议通讯的面向字节流的阻塞实现。对于用 SSLServerSocket 及 SSLSocket 编写的服务器 程序和客户程序, 他们在运行过程中常常会阻塞。例如, 当一个线程执行 SSLServerSocket 的 accept() 方法时, 假如没有客户连接, 该线程就会一直等到有客户连接才从 accept() 方 法返回 ; 再例如, 当线程执行 SSLSocket 的 read() 方法时, 如果输入流中没有数据, 该线程 就会一直等到读入足够的数据才从 read() 方法返回。假如服务器程序需要同时与多个客 户通信, 就必须分配多个工作线程, 让他们分别负责与一个客户通信, 当然每个工作线程都 有可能经常处于长时间的阻塞状态。
对 于 SSL 阻塞通信 的方式 而言, 通常需 要较 大的 系统 开销, 并且 工作 线程 的 许多时间都浪费在阻塞 I/O 操作上, 从而导致性能较慢, 通信效率较低。再者, JDK 的 SSLServerSocket 隐藏了 SSL 协议的握手交互过程, 将 SSL 协议的握手交互过程做了高度的 封装, 从而导致相关技术人员无法查看具体的握手交互过程, 无法获取到握手交互过程中 的相关报文。然而, 在诸多面向 SSL 协议的应用中, 都需要通过获知具体的握手交互过程及 来处理基于 SSL 协议的握手交互。例如, 对电子商务平台中使用的秒杀器产生的 相关报文, https 请求分析, 或者, 对其他爬虫软件模拟的 https 请求分析, 或者, 建立支持 SSL 协议的 服务器等。
SSL 非阻塞通信的方式在 JDK 的 1.4 版被引入 Java 语言, 采用这种方式, 服务器
程序接收客户连接, 客户程序建立与服务器的连接, 以及服务器程序和客户程序收发数据 的操作都可以按非阻塞的方式进行。 并且, 服务器程序只需要创建一个线程, 就能完成同时 与多个客户通信的任务。尽管 SSL 非阻塞通信的方式解决了 SSL 阻塞通信方式所存在的系 统开销大、 性能较慢、 通信效率较低的问题, 但是在安全上不支持 SSL 协议的握手交互。具 体而言, 由于 JDK 的 1.4 版中通过新的 I/O 库 (JavaNIO) 实现非阻塞通信, NIO 库包含了文 件、 管道以及客户机和服务器套接字的非阻塞功能, 然而, 库中缺少的一个特性是安全的非 阻塞套接字连接。在 Java NIO 库中没有建立安全的非阻塞通道类, 故不能使用安全的非阻 塞通信。
因此, 目前需要本领域技术人员迫切解决的一个技术问题就是 : 提出一种可以支 持 SSL 协议握手交互的非阻塞通信机制, 既能保证进行 SSL 协议非阻塞的高性能通讯, 又能 控制整个 SSL 协议的握手交互过程, 并易于获取握手交互过程中的相关报文。 发明内容
本申请所要解决的技术问题是提供一种 SSL 非阻塞通信的方法, 用以保证进行 SSL 协议非阻塞的高性能通讯, 又能控制整个 SSL 协议的握手交互过程, 并易于获取握手交 互过程中的相关报文。本申请还提供了一种用于 SSL 非阻塞通信的服务器, 用以保证上述方法在实际中 的应用及实现。
为了解决上述问题, 本申请公开了一种 SSL 非阻塞通信的方法, 包括 :
步骤 S101、 服务器监听网络 I/O 事件, 并获取所监听到网络 I/O 事件的类型 ; 若 为连接事件, 则执行步骤 S102 ; 若为读事件, 则执行步骤 S103 ; 若为写事件, 则执行步骤 S110 ;
步骤 S102、 依据所述连接事件注册读事件, 返回步骤 S101 ;
步骤 S103、 执行从网络中获取第一加密数据的读操作, 并将所述第一加密数据写 入预置的缓冲区中, 转步骤 S104 ;
步骤 S104、 依据预设的 SSL 握手过程获取当前握手状态, 若所述握手状态为数据 解密, 则执行步骤 S105 ; 若所述握手状态为数据加密, 则执行步骤 S109 ;
步骤 S105、 对所述缓冲区中的第一加密数据进行解密, 若解密成功, 获得第一数 据, 则执行步骤 S106, 若解密不成功, 则执行步骤 S108 ;
步骤 S106、 判断解密获得的第一数据是否为客户端请求原文, 若是, 则结束本次 SSL 握手过程 ; 若否, 则执行步骤 S107 ;
步骤 S107、 将所述第一数据写入缓冲区, 并返回步骤 S104 ;
步骤 S108、 注册读事件, 并返回步骤 S101 ;
步骤 S109、 对所述缓冲区中的第一数据进行加密, 获得第二加密数据, 注册写事 件, 返回步骤 S101 ;
步骤 S110、 执行将所述缓冲区中的第二加密数据写入网络的写操作, 转步骤 S104。
优选的, 在所述握手状态为任务执行操作时, 所述的方法还包括 :
步骤 S111、 执行当前握手任务, 执行完后返回步骤 S104。
优选的, 所述第一加密数据包括加密的客户端请求原文或客户端加密的握手报 文; 所述第一数据为客户端请求原文或握手报文 ; 所述第二加密数据为服务器加密的握手 报文。
优选的, 所述缓冲区包括输入缓冲区和输出缓冲区, 所述步骤 S103 中的第一加密 数据写入输入缓冲区, 所述步骤 S107 中的第一数据写入输入缓冲区 ;
所述步骤 S109 为对输出缓冲区中的第一数据进行加密, 在进行加密之前, 还包 括: 从输入缓冲区中读出第一数据并写入输出缓冲区 ;
所述步骤 S110 为, 执行将输出缓冲区中的第二加密数据写入网络的写操作。
优选的, 所述步骤 S105 中对缓冲区中的第一加密数据进行解密的步骤具体包括 :
从输入缓冲区中读指针的起始位置开始读取预设大小的第一加密数据 ;
对所读取的第一加密数据进行解密。
优选的, 在所述步骤 S107 将第一数据写入输入缓冲区后, 还包括 :
将输入缓冲区中的读指针移至第一数据的首位。
优选的, 在所述步骤 S108, 注册读事件之前还包括 :
提示当前缓冲区的数据不足, 将读指针移至输入缓冲区中经过解密处理的第一加 密数据之后。
优选的, 在所述步骤 S109 对第一数据进行加密之前, 还包括 :
将写指针移至写入输出缓冲区中的第一数据的首位。
优选的, 所述步骤 S109 中将第一数据写入输出缓冲区的步骤为 :
从输出缓冲区中写指针的起始位置开始在输出缓冲区中写入预设大小的第一数 据。
本申请还公开了一种用于 SSL 非阻塞通信的服务器, 包括 :
监听模块, 用于监听网络 I/O 事件, 并获取所监听到网络 I/O 事件的类型 ; 若为连 接事件, 则触发连接事件处理模块 ; 若为读事件, 则触发读事件处理模块 ; 若为写事件, 则 触发写事件处理模块 ;
连接事件处理模块, 用于依据所述连接事件注册读事件, 然后调用所述监听模 块;
读事件处理模块, 用于执行从网络中获取第一加密数据的读操作, 并将所述第一 加密数据写入预置的缓冲区中, 然后触发握手控制模块 ;
握手控制模块, 用于依据预设的 SSL 握手过程获取当前握手状态, 若所述握手状 态为数据解密, 则触发解密操作模块 ; 若所述握手状态为数据加密, 则触发加密操作模块 ;
解密操作模块, 用于对所述缓冲区中的第一加密数据进行解密, 若解密成功, 获得 第一数据, 则触发报文判断模块, 若解密不成功, 则触发读事件注册模块 ;
报文判断模块, 用于判断解密获得的第一数据是否为客户端请求原文, 若是, 则触 发结束模块 ; 若否, 则触发缓存写入模块 ;
结束模块, 用于结束本次 SSL 握手过程 ;
缓存写入模块, 用于将所述第一数据写入缓冲区, 并调用握手控制模块 ;
读事件注册模块, 用于注册读事件, 并调用监听模块 ;
加密操作模块, 用于对所述缓冲区中的第一数据进行加密, 获得第二加密数据, 注册写事件, 然后调用监听模块 ;
写事件处理模块, 用于执行将所述缓冲区中的第二加密数据写入网络的写操作, 然后调用握手控制模块。
与现有技术相比, 本申请具有以下优点 :
针对现有的 SSL 非阻塞通信的方式在安全上不支持 SSL 协议的握手交互的问题, 本申请直接面向通信底层提供了一种安全的 SSL 非阻塞通讯的轮循框架, 在该轮循框架 中, 以事件机制贯穿 SSL 握手和 NIO 无阻塞通讯之间, 并利用缓冲区来传递数据。 具体而言, 本申请有效整合了 NIO 无阻塞和 SSLEngine 握手的复杂事件机制, 解决了握手状态和情形 引发的通讯事件的处理。 在通讯和握手过程中, 将缓冲区做为共同利用的区域进行操作, 通 过对缓冲区的读写准备和压紧处理, 高效支持无阻塞通讯和握手交互。从而既能保证进行 SSL 协议非阻塞的高性能通讯, 又能控制整个 SSL 协议的握手交互过程, 并易于获取握手交 互过程中的相关报文, 解决了诸多面向 SSL 协议的应用问题。 附图说明
图 1 是本申请的一种 SSL 非阻塞通信的方法实施例 1 的步骤流程图 ; 图 2 是本申请的一种 SSL 非阻塞通信的方法实施例 2 的步骤流程图 ; 图 3 是本申请的一种用于 SSL 非阻塞通信的服务器的结构框图。具体实施方式
为使本申请的上述目的、 特征和优点能够更加明显易懂, 下面结合附图和具体实 施方式对本申请作进一步详细的说明。
为使本领域技术人员更好地理解本申请, 以下简单介绍本申请非阻塞通信的基本 思想 :
假如要同时做两件事 : 烧开水和烧粥。
烧开水的步骤如下 :
锅里放水, 打开煤气炉 ;
等待水烧开 ; // 阻塞
关闭煤气炉, 把开水灌到水壶里。
烧粥的步骤如下 :
锅里放水和米, 打开煤气炉 ;
等待粥烧开 ; // 阻塞
调整煤气炉, 改为小火 ;
等待粥烧熟 ; // 阻塞
关闭煤气炉。
为了同时完成两件事, 一个方案是同时请两个人分别做其中的一件事, 这相当于 采用多线程来同时完成多个任务。
还有一种方案是让一个人同时完成两件事, 这个人应该善于利用一件事的空闲时 间去做另一件事, 一刻也不应该闲着 :
锅子里放水, 打开煤气炉 ; // 开始烧水锅子力放水和米, 打开煤气炉 ; // 开始烧粥
while( 一直等待, 直到有水烧开, 粥烧开或粥烧熟事件发生 ){// 阻塞
if( 水烧开 )
关闭煤气炉, 把开水灌到水壶里 ;
if( 粥烧开 )
调整煤气炉, 改为小火 ;
if( 粥烧熟 )
关闭煤气炉 ;
if( 水已经烧开并且粥已经烧熟 )
退出循环 ;
}// 这里的煤气炉可以理解为每件事就有一个煤气炉配给
这个人不断监控烧水及烧粥的状态, 如果发生了″水烧开″,″粥烧开″或″粥 烧熟″事件, 就去处理这些事件, 处理完一件事后进行监控烧水及烧粥的状态, 直到所有的 任务都完成。
以上工作方式也可以运用到服务器程序中, 服务器程序只需要一个线程就能同时 负责接收客户的连接, 接收各个客户发送的数据, 以及向各个客户发送响应数据 . 服务器 程序的处理流程如下 :
while( 一直等待, 直到有接收连接就绪事件, 读就绪事件或写就绪事件发生 ){// 阻塞
if( 有客户连接 )
接收客户的连接 ; // 非阻塞
if( 某个 Socket 的输入流中有可读数据 )
从输入流中读数据 ; // 非阻塞
if( 某个 Socket 的输出流可以写数据 )
向输出流写数据 ; // 非阻塞
}
以上处理流程采用了轮询的工作方式, 当某一种操作就绪时, 就执行该操作, 否则 就查看是否还有其他就绪的操作可以执行。线程不会因为某一个操作还没有就绪, 就进入 阻塞状态, 一直等待这个操作就绪。
为了使轮询的工作方式顺利进行, 接收客户的连接, 从输入流读数据, 以及, 向输 出流写数据的操作都应该以非阻塞的方式运行。所谓非阻塞, 就是指当线程执行这些方法 时, 如果操作还没有就绪, 就立即返回, 而不会一直等到操作就绪。例如, 当线程接收客户 连接时, 如果没有客户连接, 就立即返回 ; 再例如, 当线程从输入流中读数据时, 如果输入流 中还没有数据, 就立即返回, 或者如果输入流还没有足够的数据, 那么就读取现有的数据, 然后返回。以上 while 条件中的操作还是按照阻塞方式进行的, 如果未发生任何事件, 就 会进入阻塞状态, 直到接收连接事件, 读事件或写事件中至少有一个事件发生时, 才会执行 while 循环体中的操作。在 while 循环体中, 一般会包含在特定条件下退出循环的操作。
本申请的核心构思之一在于, 直接面向通信底层提供一种实现 SSL 非阻塞通讯的 轮循框架, 在该轮循框架中, 以事件机制贯穿 SSL 握手和 NIO 通讯之间, 并利用缓冲区来传递数据, 从而既能保证进行 SSL 协议非阻塞的高性能通讯, 又能控制整个 SSL 协议的握手交 互过程, 并易于获取握手交互过程中的相关报文, 解决了诸多面向 SSL 协议的应用问题。
参考图 1, 示出了本申请的一种 SSL 非阻塞通信的方法实施例 1 的步骤流程图, 具 体可以包括以下步骤 :
步骤 S101、 服务器监听网络 I/O 事件, 并获取所监听到网络 I/O 事件的类型 ; 若 为连接事件, 则执行步骤 S102 ; 若为读事件, 则执行步骤 S103 ; 若为写事件, 执则行步骤 S110 ;
在具体实现中, 可以建立一个基于 java.nio 包 ( 新 I/O 包 ) 的非阻塞服务器, 该 服务器接收客户端连接, 客户端建立与服务器的连接, 以及服务器和客户端收发数据的操 作都可以按非阻塞的方式进行。非阻塞的通信机制主要由 java.nio 包中支持非阻塞通信 的类实现, 如 Selector 和 SelectionKey 等。
在所述服务器上可以设置监听端口, 并定义需要监听的网络 I/O 事件, 当监听 到某个事件发生时, 则处理这个事件。所述 “监听”可以理解为不停地选择搜索到的事 件信息。作为本申请实施例应用的一种示例, 可以通过向选择器 Selector 注册网络 I/ O 事件来委托 Selector 监控网络 I/O 事件, Selector 则会监听这些事件, 获取所监听到 网络 I/O 事件的类型, 并依据类型设置 SelectionKey。具体而言, Selector 采用了多路 复用 (Multiplexing) 技术, 可在一个选择器上处理多个套接字, 通过获取读写通道来进 行 IO 操作。当向 Selector 注册事件时, 可以在参数中指定 SelectionKey 感兴趣的事件, 从而创建一个 SelectionKey 对象, 这个 SelectionKey 对象是用来跟踪注册事件的句柄, SelectionKey 对象的有效期间, Selector 会一直监控与 SelectionKey 对象相关的事件。 在本申请一种优选的实施例中, 所述网络 I/O 事件包括如下三种类型 :
连接事件 accept : 当客户端请求被服务器接受后触发该事件。该事件表明一个新 的客户端与服务器正式建立连接。
读事件 read : 表示网络中已经有了可读数据, 可以执行读操作了 ;
以及, 写事件 write : 表示已经可以向网络写数据了。
相 应 的 SelectionKey 为 : SelectionKey.OP_ACCEPT : 连 接 事 件, SelectionKey. OP_READ : 读事件, 以及, SelectionKey.OP_WRITE : 写事件。
步骤 S102、 依据所述连接事件注册读事件, 返回步骤 S101 ;
在具体实现中, 当检测到客户端的 HTTPS 的访问请求时, 将接受该连接事件响应, 并注册感兴趣事件为读事件, 然后返回由服务器继续监听。 其中, HTTPS(Secure Hypertext Transfer Protocol, 安全超文本传输协议 ) 是以安全为目标的 HTTP 通道, 即 HTTP 下加入 SSL 层, 用于对数据进行压缩和解压操作, 并返回网络上传送回的结果。
作为具体应用的一种示例, 可以通过以下代码向 Selector 注册读事件 :
SelectionKey key = SSLServerSocket.register(selector, SelectionKey.OP_ READ)
步骤 S103、 执行从网络中获取第一加密数据的读操作, 并将所述第一加密数据写 入预置的缓冲区中, 转步骤 S104 ;
当服务器监听到读事件时, 表示网络中已经有了可读数据, 可以执行读操作了, 于 是从网络中读取客户端发送的第一加密数据。在具体实现中, 所述第一加密数据为客户端
加密的客户端请求原文或客户端加密的握手报文, 并且通常为字节流数据。在本申请实施 例中, 所述网络可以理解为通道 (channel), 即当服务器与某个客户端建立连接后, 则在该 客户端与服务器之间打开了一个通道。通道可以用来连接缓冲区与数据源或数据汇 ( 数 据目的地 ), 也就是说, 数据源的数据可以经过通道到达缓冲区, 缓冲区的数据经过通道到 达数据汇, 本步骤即为客户端 ( 数据源 ) 发送的数据经过通道到达缓冲区。具体可以采 用参数 read(ByteBufferbuffer) 来接收第一加密数据, 把它们存放到参数指定的缓冲区 ByteBuffer 中。
在非阻塞模式下, 读操作采用能读到多少数据就读多少数据的原则, 具体可以通 过 read() 方法实现。read() 方法读取当前通道中的可读数据, 有可能不足 r 个字节 (r 为 完整报文的字节 ), 或者为 0 个字节, read() 方法总是立即返回, 而不会等到读取了 r 个字 节再返回。
步骤 S104、 依据预设的 SSL 握手过程获取当前握手状态, 若所述握手状态为数据 解密, 则执行步骤 S105 ; 若所述握手状态为数据加密, 则执行步骤 S109 ;
在 具 体 实 现 中, SSL 握 手 过 程 可 以 在 SSL 握 手 引 擎 (SSLEngine) 中 设 置, 由 SSLEngine 控制 SSL 握手过程, 并进行握手状态检测和处理。公知的是, 一次 SSL 连接的完 整过程包括 :
单向认证 : 客户端向服务器发送消息, 服务器接到消息后, 用服务器的密钥库中的 私钥对数据进行加密, 然后把加密后的数据和服务器的公钥一起发送到客户端, 客户端用 服务器发送来的公钥对数据解密, 然后再用传到客户端的服务器公钥对数据加密传给服务 器, 服务器用私钥对数据进行解密。
双向认证 :
(1) 客户端向服务器发送消息, 首先把消息用客户端证书加密然后连同时把客户 端证书一起发送到服务器 ;
(2) 服务器接到消息后首先用客户端证书把消息解密, 然后用服务器私钥把消息 加密, 把服务器证书和消息一起发送到客户端 ;
(3) 客户端用发来的服务器证书对消息进行解密, 然后用服务器的证书对消息加 密, 然后在用客户端的证书对消息在进行一次加密, 连同加密消息和客户端证书一起发送 到服务器 ;
(4) 服务器首先用客户端传来的证书对消息进行解密, 确保消息是这个客户发来 的, 然后用服务器的私钥对消息再进行解密这个便得到了明文数据。
可以看出, 基于 SSLEngine 检测到的握手状态至少可以包括 : 数据加密 ( 如服务器 用私钥对数据进行加密 ) 和数据解密 ( 如服务器用私钥对数据进行解密 )。
步骤 S105、 对所述缓冲区中的第一加密数据进行解密, 若解密成功, 获得第一数 据, 则执行步骤 S106, 若解密不成功, 则执行步骤 S108 ;
当检测到的握手状态为数据解密时, 则针对缓冲区中的第一加密数据, 如加密的 客户端请求原文或加密的握手报文进行解密, 若解密成功, 则获得第一数据为客户端请求 原文或握手报文。
步骤 S106、 判断解密获得的第一数据是否为客户端请求原文, 若是, 则结束本次 SSL 握手过程 ; 若否, 则执行步骤 S107 ;步骤 S107、 将所述第一数据写入缓冲区, 并返回步骤 S104 ;
若解密获得的第一数据为客户端请求原文, 则可以结束本次 SSL 握手过程 ; 若解 密获得的第一数据为握手报文, 则将该握手报文写入缓冲区, 返回 SSLEngine 检测的步骤 以进行下一步握手操作, 如进行数据加密操作, 即在下一步握手操作中对该握手报文进行 服务器加密。
步骤 S108、 注册读事件, 并返回步骤 S101 ;
如果对所述缓冲区中的第一加密数据解密不成功, 通常表示写入缓冲区中的第一 加密数据不是完整的加密报文, 需要继续从网络中获得第一加密数据, 因而注册一个读事 件, 然后返回服务器监听网络 I/O 事件的步骤。
步骤 S109、 对所述缓冲区中的第一数据进行加密, 获得第二加密数据, 注册写事 件, 返回步骤 S101 ;
当检测到的握手状态为数据加密时, 则针对缓冲区中的第一数据, 如握手报文进 行加密, 则获得第二加密数据为服务器加密的握手报文。由于需要将所述第二加密数据写 入网络, 因而注册一个写事件, 然后返回服务器监听网络 I/O 的步骤。
步骤 S110、 执行将所述缓冲区中的第二加密数据写入网络的写操作, 转步骤 S104。 当服务器监听到写事件时, 表示已经可以向网络写数据了, 于是将缓冲区中的第 二加密数据写入网络。 在具体实现中, 所述第二加密数据为服务器加密的握手报文, 具体可 以采用 write(ByteBuffer buffer) : 把指定的缓冲区 ByteBuffer 中的第二加密数据发送 出去。
在非阻塞模式下, 写操作奉行能输出多少数据就输出多少数据的原则, 具体可以 通过 write() 方法实现。write() 方法向通道输出数据, 有可能不足 r 个字节 (r 为完整报 文的字节 ), 或者为 0 个字节, write() 方法总是立即返回, 而不会等到输出 r 个字节后再返 回。
在具体实现中, 服务器接受客户端请求, 同时将读、 写通道提交由相应的读线程 (Reader) 和写服务线程 (Writer), 由读写线程分别完成对客户端数据的读取和对客户端 的回应操作。 具体而言, 服务器接受客户端请求后, 控制线程将该请求的读通道交给读线程 池, 由读线程池分配线程完成对客户端数据的读取操作 ; 当读线程完成读操作后, 将数据返 回控制线程, 进行服务器的业务处理 ; 完成业务处理后, 将需回应给客户端的数据和写通道 提交给写线程池, 由写线程完成向客户端发送回应数据的操作。 由于网络带宽等原因, 在通 道的读、 写操作中是容易出现等待的, 所以在读、 写操作中引入多线程, 对性能提高明显, 而 且可以提高客户端的感知服务质量。
参考图 2, 示出了本申请的一种 SSL 非阻塞通信的方法实施例 2 的步骤流程图, 具 体可以包括 :
步骤 S201、 服务器监听网络 I/O 事件, 并获取所监听到网络 I/O 事件的类型 ; 若 为连接事件, 则执行步骤 S202 ; 若为读事件, 则执行步骤 S203 ; 若为写事件, 执则行步骤 S210 ;
步骤 S202、 依据所述连接事件注册读事件, 返回步骤 S201 ;
步骤 S203、 执行从网络中获取第一加密数据的读操作, 并将所述第一加密数据写
入预置的输入缓冲区中, 转步骤 S204 ;
步骤 S204、 依据预设的 SSL 握手过程获取当前握手状态, 若所述握手状态为数据 解密, 则执行步骤 S205 ; 若所述握手状态为数据加密, 则执行步骤 S209 ; 若所述握手状态为 任务执行操作时, 则执行步骤 S211 ;
步骤 S205、 从输入缓冲区中读指针的起始位置开始读取预设大小的第一加密数 据, 对所读取的第一加密数据进行解密, 若解密成功, 获得第一数据, 则执行步骤 S206, 若解 密不成功, 则执行步骤 S208 ;
步骤 S206、 判断解密获得的第一数据是否为客户端请求原文, 若是, 则结束本次 SSL 握手过程 ; 若否, 则执行步骤 S207 ;
步骤 S207、 将所述第一数据写入输入缓冲区, 并将输入缓冲区中的读指针移至第 一数据的首位, 返回步骤 S204 ;
步骤 S208、 提示当前缓冲区的数据不足, 将读指针移至输入缓冲区中经过解密处 理的第一加密数据之后, 然后注册读事件, 并返回步骤 S201 ;
步骤 S209、 从输入缓冲区中读出第一数据, 并从输出缓冲区中写指针的起始位置 开始在输出缓冲区中写入预设大小的第一数据, 对所述输出缓冲区中的第一数据进行加 密, 获得第二加密数据, 注册写事件, 返回步骤 S201 ; 步骤 S210、 执行将输出缓冲区中的第二加密数据写入网络的写操作, 将写指针移 至输出缓冲区中已写入网络的第二加密数据之后, 然后转步骤 S204。
步骤 S211、 执行当前握手任务, 执行完后返回步骤 S204。
例如, 所述握手任务为获取密钥套件或获取证书, 则服务器执行相应的获取密钥 套件或获取证书的操作。
为使本领域技术人员更好地理解本申请, 以下通过一个具体例子说明。
( 一 ) 服务器监听到连接事件, 接受所述连接事件响应并注册读事件, 然后继续监 听。
( 二 ) 服务器监听到读事件, 表示可以执行读操作了, 于是执行从网络中获取第一 加密数据的读操作, 并将所述第一加密数据写入预置的缓冲区中 ; 其中, 第一加密数据为客 户端加密的请求原文或客户端加密的握手报文 ;
然后, 基于 SSLEngine 检测当前的握手状态, 若为服务器采用私钥进行数据解密, 则采用预置的私钥对所述第一加密数据进行解密, 若解密获得的是客户端请求原文, 表示 握手已经完成, 于是结束本次的 SSL 握手过程 ; 若解密获得的是握手报文, 则将该握手报文 写入输入缓冲区, 然后返回由 SSLEngine 继续检测握手状态。若解密不成功, 则表示当前输 入缓冲区中的数据不是完整的报文, 需要注册读事件以获取更多的网络数据, 于是将输入 缓冲区压紧 ( 将读指针放到处理完的数据后面 ), 然后注册读事件, 再返回由服务器继续监 听网络 1/O 事件 ;
如果 SSLEngine 检测当前的握手状态为服务器采用私钥进行数据加密, 于是对输 出缓冲区进行读写准备 ( 调整输出缓冲区的写指针, 获取写指针对应的数据位置 ), 将输出 缓冲区中的握手报文采用私钥进行加密后, 注册写事件, 返回由服务器继续监听网络 1/O 事件。
( 三 ) 服务器监听到写事件, 表示可以执行写操作了, 于是将输出缓冲区中的第二
加密数据写入网络, 写入后再将输出缓存压紧, 返回 SSLEngine 检测的步骤进行轮循。
需要说明的是, 对于方法实施例, 为了简单描述, 故将其都表述为一系列的动作组 合, 但是本领域技术人员应该知悉, 本申请并不受所描述的动作顺序的限制, 因为依据本申 请, 某些步骤可以采用其他顺序或者同时进行。其次, 本领域技术人员也应该知悉, 说明书 中所描述的实施例均属于优选实施例, 所涉及的动作和模块并不一定是本申请所必须的。
参考图 3, 示出了本申请的一种用于 SSL 非阻塞通信的服务器的结构框图, 具体可 以包括以下模块 :
监听模块 301, 用于监听网络 I/O 事件, 并获取所监听到网络 I/O 事件的类型 ; 若 为连接事件, 则触发连接事件处理模块 302 ; 若为读事件, 则触发读事件处理模块 303 ; 若为 写事件, 则触发写事件处理模块 310 ;
连接事件处理模块 302, 用于依据所述连接事件注册读事件, 然后调用所述监听模 块 301 ;
读事件处理模块 303, 用于执行从网络中获取第一加密数据的读操作, 并将所述第 一加密数据写入预置的缓冲区中, 然后触发握手控制模块 304 ;
握手控制模块 304, 用于依据预设的 SSL 握手过程获取当前握手状态, 若所述握手 状态为数据解密, 则触发解密操作模块 305 ; 若所述握手状态为数据加密, 则触发加密操作 模块 310 ; 解密操作模块 305, 用于对所述缓冲区中的第一加密数据进行解密, 若解密成功, 获得第一数据, 则触发报文判断模块 306, 若解密不成功, 则触发读事件注册模块 309 ;
报文判断模块 306, 用于判断解密获得的第一数据是否为客户端请求原文, 若是, 则触发结束模块 307 ; 若否, 则触发缓存写入模块 308 ;
结束模块 307, 用于结束本次 SSL 握手过程 ;
缓存写入模块 308, 用于将所述第一数据写入缓冲区, 并调用握手控制模块 304 ;
读事件注册模块 309, 用于注册读事件, 并调用监听模块 301 ;
加密操作模块 310, 用于对所述缓冲区中的第一数据进行加密, 获得第二加密数 据, 注册写事件, 然后调用监听模块 301 ;
写事件处理模块 311, 用于执行将所述缓冲区中的第二加密数据写入网络的写操 作, 然后调用握手控制模块 304。
在本申请的一种优选实施例中, 在所述握手状态为任务执行操作时, 还包括 :
任务执行模块, 用于执行当前握手任务, 执行完后调用握手控制模块。
在具体实现中, 所述第一加密数据可以为加密的客户端请求原文或客户端加密的 握手报文 ; 所述第一数据可以为客户端请求原文或握手报文 ; 所述第二加密数据可以为服 务器加密的握手报文。
所述缓冲区可以包括输入缓冲区和输出缓冲区, 所述第一加密数据和第一数据可 以写入输入缓冲区, 第二加密数据可以写入输出缓冲区。
由于本实施例基本相应于前述图 1 和图 2 所示的方法实施例, 故本实施例的描述 中未详尽之处, 可以参见前述实施例中的相关说明, 在此就不赘述了。
需要说明的是, 本申请装置实施例和系统实施例中所涉及的模块、 子模块和单元 可以为软件, 可以为硬件, 也可以为软件和硬件的组合。
本申请可用于众多通用或专用的计算系统环境或配置中。 例如 : 个人计算机、 服务 器计算机、 手持设备或便携式设备、 平板型设备、 多处理器系统、 基于微处理器的系统、 置顶 盒、 可编程的消费电子设备、 网络 PC、 小型计算机、 大型计算机、 包括以上任何系统或设备的 分布式计算环境等等。
本申请可以在由计算机执行的计算机可执行指令的一般上下文中描述, 例如程序 模块。 一般地, 程序模块包括执行特定任务或实现特定抽象数据类型的例程、 程序、 对象、 组 件、 数据结构等等。也可以在分布式计算环境中实践本申请, 在这些分布式计算环境中, 由 通过通信网络而被连接的远程处理设备来执行任务。在分布式计算环境中, 程序模块可以 位于包括存储设备在内的本地和远程计算机存储介质中。
最后, 还需要说明的是, 在本文中, 诸如第一和第二等之类的关系术语仅仅用来将 一个实体或者操作与另一个实体或操作区分开来, 而不一定要求或者暗示这些实体或操作 之间存在任何这种实际的关系或者顺序。而且, 术语 “包括” 、 “包含” 或者其任何其他变体 意在涵盖非排他性的包含, 从而使得包括一系列要素的过程、 方法、 物品或者设备不仅包括 那些要素, 而且还包括没有明确列出的其他要素, 或者是还包括为这种过程、 方法、 物品或 者设备所固有的要素。在没有更多限制的情况下, 由语句 “包括一个 ......” 限定的要素, 并不排除在包括所述要素的过程、 方法、 物品或者设备中还存在另外的相同要素。
以上对本申请所提供的一种 SSL 非阻塞通信的方法以及一种用于 SSL 非阻塞通 信的服务器进行了详细介绍, 本文中应用了具体个例对本申请的原理及实施方式进行了阐 述, 以上实施例的说明只是用于帮助理解本申请的方法及其核心思想 ; 同时, 对于本领域的 一般技术人员, 依据本申请的思想, 在具体实施方式及应用范围上均会有改变之处, 综上所 述, 本说明书内容不应理解为对本申请的限制。