第 4 章 传输

本节主要内容有以下几个方面

  • OIO——阻塞传输
  • NIO——异步传输
  • Embedded——测试 ChannelHandler

4.1 案例

4.1.1 java 版本的OIO 和 NIO

    代码后续不上

4.1.2 Netty 版本的 OIO 和 NIO

    代码后续不上

4.2 传输 API

    传输 API 的核心就是 Channel 接口,它被用于所有的 IO 操作。

    每一个 Channel 都会被分配一个 ChannelPipeLine 和 ChannelConfig,ChannelConfig 包含 Channel 的所有配置。每一个Channel 都是独一无二的。前面我们说过 ChannelPipeLine 持有所有的 ChannelHandler 的实例,形成一个 ChannelHandler 链,使得数据在链中可以顺序流动。在这里,ChannelPipeLine 其实是实现了一种设计模式——拦截过滤器(Intercepting Filter)。从而使得你可以通过自己的需要添加或者删除 ChannelHandler 实例来修改 ChannelPipeLine。

    Channel 一些重要的方法

方法名     描述
eventLoop 返回分配 Channel 的EventLoop
pipeLine    返回分配给 Channel 的 ChannelPipeLine
isActive 如果 Channel 是活动的(例如:一个Socket 传输连接到了远程),则返回 true
localAddress 返回本地的 SocketAddress
remoteAddress 返回远程的 SocketAddress
write 将数据冲刷到远程节点。这个数据被传输到 ChannelPipeLine ,并且排队直到被冲刷
flush 将之前已写好的数据冲刷到底层传输
writeAndFlush    连续调用 write 和 flush

    Netty 的 Channel 实现是线程安全的,当多个线程同时使用 Channel 冲刷数据时,也不会出现线程安全问题。因为处理每一个 Channel 数据流的实际上是 EventLoop,而每一个 Channel 只会和一个 EventLoop 绑定,每一个 EventLoop 又只属于一个线程。

4.3 一些内置的传输

    Netty 提供一些可开箱即用的内置传输方式。所以理解这些传输方式对于我们的应用实践大有裨益。Netty 所提供的传输如下

  •     NIO——使用 java.nio.channels 包作为基础(基于选择器的方式)
  •     Epoll——有 JNI 驱动的 epoll()和非阻塞 IO
  •     OIO——使用 java.net 包作为基础(使用阻塞流)
  •     Local——可以在 JVM 内部通过管道进行通信的本地传输
  •    Embedded——Embedded传输,允许使用 ChannelHander 而又不需要一个真正的基于网络环境的传输。方便测试     ChannelHandler

 4.3.1 NIO——非阻塞IO

    NIO 的实现核心在于选择器(Selector详情)。选择器作用,简单说来,就是可以筛选出注册在该选择器中指定状态的通道,然后使用该通道去完成想要完成任务。每一个 Channel 最多可以有 4 种状态:

    AcceptAble(OP_ACCEPT):新的 Channel 已被接收且就绪的状态

    Connectable(OP_CONNECT):Channel 连接已经完成的状态

    Readable(OP_READ):Channel 有已就好的可读的数据

    WriteAble(OP_WRITE):Channel 可用于写数据

    上面这些状态可以在把 Channel 注册到选择器的阶段指定,类似于下面这样

channel.configureBlocking(false);
//向 selcetor 中注册一个Channel,选择选择该 Channel 的条件是该 Channel 达到 Readable 状态
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);

channel.configureBlocking(false);
//向 selcetor 中注册一个Channel,选择器选择该 Channel 的条件是 Channel 达到 Readable 或者 Writeable 状态
SelectionKey key = channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE)

    一个 Channel 在注册到选择器的阶段,至少应该指定一种状态,否则该 Channel 永远不会被执行。在这里就体现了一种事件驱动的概念,即每当 Channel 达到某种事先指定好的状态后,就可以被选择器选中,然后去执行相关的操作。 

    前面这些其实都是基于 java NIO 中关于 Selector 原理的一个简单描述,在 Netty 中,已经把这些内部细节完全隐藏起来了,只对外暴露了一个很简单的 API,方便用户的使用。一个完整的 选择器处理达到指定状态 Channel 示意图如下

    

    注:当有多个同时达到指定状态的 Channel 时,都会被选择器选中的。

4.3.2 Epoll——用于 Linux 的本地非阻塞传输

    Epoll,具有一个高可扩展性的 IO 事件通知特性。在 Linux 系统推荐使用它。它的用法和 NIO 基本一样,只需要把 NIOEventLoopGroup 替换为 EpollEventLoopGroup,以及把 NioServerSocketChannel.class 替换为 EpollServerSocketChannel.class 即可。

4.3.3 Embeded传输

    主要用于本地测试编写的 ChannelHandler 逻辑,具体的测试用例将在后面的章节进行说明


总结

    本章对 Netty 提供的一些传输方式进行了说明,下一章将会对 Netty 提供的存储数据的容器 ByteBuf 和 ByteBufHolder 进行详细说明

    

猜你喜欢

转载自blog.csdn.net/yhs1296997148/article/details/80383912