Java网络编程中,OIO和NIO的网络模型是截然不同的,然而Netty为所有阻塞和非阻塞的IO提供了一个通用的API,使用这个API,可以简化不同传输的改变,屏蔽了上层的感知
我们看下不使用Netty来使用NIO和OIO
上面是一段阻塞式的方法获取连接的应用程序,如果改为了非阻塞的话,需要完全的重写吧
而使用Netty实现就会完全不一样
非阻塞版本只需要将EventLoopGroup从原本的OIO的EventLoopGroup改为
new NioEventLoopGroup
channel改为 NioServerSocketChannel.class
这样,Netty为每种传输的实现暴露了相同的API
这样外部的代码基本可以不受影响的使用
所有需要实现的,只有ChnanelPipeline和ChannelHandler
接下来,我们说下传输的API本身
核心是interface Channel
用于所有的IO操作.Channel类层次
每个Channel都包含一个ChannelPipeline和ChannelConfig的引用持有
为了保证其有序性,Channel还额外实现了Comparable的接口
ChannelPipeline持有所有处理入站和出站事件的ChannelHandler的实例
ChannelHandler常见的用法有
将数据从一种格式进行转为另一种
提供异常通知
提供Channel的活动通知
提供当Channel注册到EventLoop或者从EventLoop注销的时候通知
提供有关用户自定义事件的通知
Channel中也有很多的其他方法
常见的在列表中
比如我们写到Channel的话,可能出现并发的问题,不过Channel的写入是线程安全的,可以保证消息按照顺序发送
Netty还内置了写传输,但是并非所有的传输都支持每一种协议,我们需要选择一个和应用程序使用协议相容的传输
提供的Netty的传输列表如下
NIO 使用java.nio.channels作为基础–基于选择器的方式
Epoll io.netty.channel.epoll 由JNI驱动的epoll和非阻塞IO,更适合在Linux上使用
OIO 使用java.net作为基础–阻塞流
Local VM内部利用管道进行本地的通信
Embedded Embedded 使用ChannelHander测试的时候使用,不需要创建一个真正的基于网络的传输
那么不同的传输协议之间的区别在于
1.NIO是一个完全的异步的实现,一个基于选择器的API
选择器就是一个注册器,我们可以将监视者注册到选择器里面,等到Channel的状态发生时候得到通知,可能的变化有
新的Channel准备好了
连接完成
Channel已经有了就绪的可以读的数据
Channel可以用于写数据
整体的传输流程如下
2.Epoll
用于Linux本地非阻塞的传输
因为Linux提供了高性能的可扩展的IO事件通知特性
性能更加的好,也是Linux上非阻塞网络编程的事实标准,JDK NIO API使用了这些epoll调用
Netty为Linux提供了一组NIO API,其以一种和其本身的设计更加一致的方式使用epoll,并且以一种更加轻量的方式使用中断,应用程序旨在运行Linux系统,epoll是合适的选择
如果要进行使用 只需要将NioEventLoopGroup替换为EpollEventLoopGroup,并且NioServerSocketChannel.class改为EpollServerSocketChannel.class
3.oio
老式的传统的传输API,建立在java.net包的阻塞上的,并不是异步的
Netty的支持手段在于设置了SO_TIMEOUT的标志,等待一个IO操作完成的最大毫秒数,操作在指定时间内没有完成,抛出一个SocketTimeout Exception的标志,Netty捕获异常并继续进行处理循环,EventLoop下一次运行时,再次尝试.
3.Local传输
Local传输,用于在同一个JVM中运行客户端和服务器程序交互,传输也不需要真正的网络流量
4.Embedded传输
方便创建单元测试用例