在看完NIO和SSLEngine集成的例子后,我们了解到并没有提供一个SSLServerSocketChannel,在SelectionKey事件发生后,通过SSLEngine的wrap和unwrap编程实现握手协议。
Tomcat中也是这种做法,我们结合BIO的思路,来看看NIO是怎么做的。

1.SSL环境准备
对于BIO方式的SSL环境的准备,以SSLServerSocket准备好为信号,通过JSSESocketFactory中设置SSLContext,并读取Tomcat的SSL相关配置,最后初始化SSLContext。
NIO的思路也是差不多,也是在NioEndpoint类中:

同样是读取Connector配置的SSLEnabled属性,作为SSL逻辑在NIO通道中的切入点。
对于JSSE实现来讲,SSLUtil实际上就是JSSESocketFactory,只不过NIO通道使用这个接口调用JSSESocketFactory:

在bind方法中,和BIO的逻辑差不多,先读取Keystore的流,然后基于这个对象生成KeyManagerFactory,由KeyManagerFactory 产生KeyManager;对于TrustManager的生成的流程和KeyManager基本类似,最后将两个参数传入SSLContext.init方法中,这样,SSLContext就实例化出来了。
然后,对于Tomcat中配置的选择的SSL协议的版本,和支持的密钥套件进行,和JSSE实现默认支持的,进行取交集:

和BIO也是类似的,这两个属性暂时缓存下来,在Acceptor通道的请求访问的时候,当创建SSLEngine,设置到SSLEngine中。(在BIO是设置到SSLServerSocket中)。

2.SSL请求访问
对于一个请求过来后,SSL的NIO的线程池前面的接收请求还是普通的socket请求没有什么太大的区别,依然是先走Acceptor线程,Acceptor线程建立的SocketChannel,然后包装成PollerEvent,加入到队列中,由Poller线程轮询遍历队列取出PollerEvent,进行selector.select操作,当SelectionKey事件触发后,直接将任务转给工作线程池。

SSL的过程在这个过程中,在Acceptor线程接到数据包后,调用setSocketOptions的属性进行SocketChannel通道的包装:

在包装SocketChannel时,如果是SSL的话,首先,通过SSLContext进行创建SSLEngine,在这个过程中,会将前面缓存下来的Tomcat配置,如已经过滤的协议支持和密码套件支持设置到SSLEngine中,然后创建SecureNioChannel通道,这个SecureNioChannel通道是Acceptor线程专门为SSL交互包装出来的,普通的socket包装的通道是NioChannel,SecureNioChannel继承与NioChannel。

SecureNioChannel的类主要作用就是前面一节中NIO+SSLEngine的思路,主要实现了handshake握手和SSL通道的数据的发送,但是需要值得注意的是,SecureNioChannel类的handshake握手是放在工作线程中的,而Poller线程中读取SelectionKey是在另一个线程中,这相当于有如下的交互方式:

Acceptor线程主要负责数据包读取,当发现新数据来了之后,包装出来一个SocketChannel通道出来,然后注册OP_READ和OP_WRITE事件,这样就相当于上图中的读写通道已经建立完成了。
Poller线程中维护一个Selector,因为读写通道已经建立完毕,所以Poller线程只管监听读写通道发送数据包,如果是普通的socket,Poller线程接收完之后直接会将请求转给工作线程池中的SocketProcessor,后续继续走对应的流程了。

但是对于SSL通道来讲,SecureNioChannel通道中含有SSLEngine,在传输数据之前,需要进行几次的握手,也就是需要像上图一样来回的发送数据,通过wrap进行入栈,通过unwrap进行出栈,一直监测SSLEngineResult.HandShakeStatus的状态,一直到状态是握手成功后,说明由SecureNioChannel已经建立完毕了安全的SSL通道,之后发送的数据同样是使用SecureNioChannel的read和write进行发送,而加密和解密都有SSLEngine的JDK实现来完成。

我们来看看SecureNioChannel通道的切入的位置,在SocketProcessor的工作任务中:

我们看到,工作线程中,是通过handshake的状态进行判断,当handshake=0的时候,握手结束,后续才有handler继续进行处理,当不是0的时候,如果没有遇到异常,需要执行,这一步很关键,也是实现了上面的框图中的Poller线程和工作线程往复交互的行为,将socket和握手状态加入到Poller中,再次关注事件,进行轮询。

最后,再来看看SecureNioChannel类中的handshake实现的内容,基本和前面一节的例子类似:















k.NIO方式SSL通道流程的更多相关文章

  1. i.BIO方式的SSL通道流程

    前面已经讲解了BIO通道的整体流程,对于SSL的流程是插在通道中的,在BIO通道的初始化的时候,根据Connector配置的SSLEnabled属性进行SSL的逻辑. 主要集中的位置在JIOEndpo ...

  2. atitit.ajax bp dwr 3.的注解方式配置使用流程总结 VO9o.....

    atitit.ajax bp dwr 3.的注解方式配置使用流程总结 VO9o..... 1. 安装配置 1 1.1. 下载  dwr.jar 1M 1 1.2. 配置注解方式..web.xml 1 ...

  3. atitit.ajax bp dwr 3.的注解方式配置使用流程总结.....

    atitit.ajax bp dwr 3.的注解方式配置使用流程总结..... 1. 下载  dwr.jar 1M 1 2. 配置注解方式..web.xml 1 3. Class 配置 2 4. 测试 ...

  4. java输入输出 -- java NIO之文件通道

    一.简介 通道是 Java NIO 的核心内容之一,在使用上,通道需和缓存类(ByteBuffer)配合完成读写等操作.与传统的流式 IO 中数据单向流动不同,通道中的数据可以双向流动.通道既可以读, ...

  5. 在Salesforce中通过 Debug Log 方式 跟踪逻辑流程

    在Salesforce中通过 Debug Log方式 跟踪逻辑流程 具体位置如下所示: Setup ---> Logs ---> Debug Logs ---> Monitored ...

  6. 格式化输出的三种方式,运算符及流程控制之if判断

    ''' 格式化输出的三种方式,运算符及流程控制之if判断 ''' # 格式化输出的三种方式 # 一.占位符 程序中经常会有这样场景:要求用户输入信息,然后打印成固定的格式 比如要求用户输入用户名和年龄 ...

  7. java socket编程开发简单例子 与 nio非阻塞通道

    基本socket编程 1.以下只是简单例子,没有用多线程处理,只能一发一收(由于scan.nextLine()线程会进入等待状态),使用时可以根据具体项目功能进行优化处理 2.以下代码使用了1.8新特 ...

  8. SSL握手流程

    一.SSL是什么? 安全套接字(SSL)协议是Web浏览器和Web服务器之间安全交换信息的协议. SSL介于应用层和TCP层之间,应用层数据不再直接传递给传输层,而是传递给SSL层,SSL层对从应用层 ...

  9. JAVA NIO之文件通道

    1.简介 通道是 Java NIO 的核心内容之一,在使用上,通道需和缓存类(ByteBuffer)配合完成读写等操作.与传统的流式 IO 中数据单向流动不同,通道中的数据可以双向流动.通道既可以读, ...

随机推荐

  1. LightOj 1220 - Mysterious Bacteria (分解质因子x=b^p 中的 x 求最大的 p)

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1220 题意:已知 x=bp 中的 x 求最大的 p,其中 x b p 都为整数 x = ...

  2. Java学习-042-获取目录文件列表(当前,级联)

    以下三个场景,在我们日常的测试开发中经常遇到: 软件自动化测试,在进行参数测试时,我们通常将所有相似功能的参数文件统一放在一个目录中,在自动化程序启动的时候,获取资源参数文件夹中所有参数文件,然后解析 ...

  3. FlipView 索引为0 WP8.1

    如果使用FlipView时,出现别的页面切换到含有FlipView的页面时(缓存此页面/MainPage),点击或者滑动FlipView,Flipview自动索引到0 的问题解决办法 1.对Flipv ...

  4. LeetCode Graph Valid Tree

    原题链接在这里:https://leetcode.com/problems/graph-valid-tree/ 题目: Given n nodes labeled from 0 to n - 1 an ...

  5. 【转】PHP实现连贯操作

    [第一种方案 __call] 我们在使用一些框架(如ThinkPHP)编码的时候,常用到这样的代码. M('User')->where(array('id'=>1))->field( ...

  6. 模板 BFS

    [模板]BFS #include <stdio.h> #include <string.h> #include <queue> using namespace st ...

  7. Plextor 浦科特M7VC性能

    浦科特一出TLC的SSD,立刻就受到了人们的关注,网上铺天盖地的评测.看了评测感觉不错,于是买了一块来用. 自己测试,似乎和网上的结果差异挺大的. 这是我自己测试的结果.(测试平台为:I7-5820K ...

  8. getopt解析命令行参数一例:汇集多个服务器的日志

    高效工作的一个诀窍就是尽可能自动化, 简便化. 比如, 公司里, 要搜索多个集群下的应用日志来排查问题, 需要使用 pssh: pssh -i -h api_hangzhou.iplist " ...

  9. Java 中System里getProperty(something)

    Java 中System里getProperty 方法获得系统参数 Key Description of Associated Value 中文描述 java.version Java Runtime ...

  10. 2016.8.16 Java培训第一天

    1. 十进制转换二进制 31/2=15余1  15/2=7余1 7/2=3余1 3/2=1余1    31的二进制结果为11111 35/2=17余1  17/2=8余1  8/2=4余0 4/2=2 ...