JAVA_NIO通信理论基础

java的NIO

包含通道Channel,缓冲区Buffer,选择器selector三个重要的类。

IO多路复用

指的是一个进程/线程可以同时监视多个文件描述符(一个网络连接,操作系统底层使用一个文件描述符来表示),一旦其中的一个或者多个文件描述符可读或者可写,系统内核就通知该进程/线程。

缓冲区Buffer

Buffer是抽象类,Buffer类是一个非线程安全类, 主要数据类型有 ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer、MappedByteBuffer(用于内存映射)。

capacity属性指容量,写入的数据对象的数量一旦初始化,就不能再改;

position属性表示当前位置,读写模式变化时,position会进行调整;limit属性表示读写的最大上限,读写模式切换时变化。

属性mark(标记)就是相当一个暂存属性,暂时保存position的值,方便后面的重复使用position值。

allocate()创建缓冲区, put()写入到缓冲区,flip()翻转(将写入模式翻转成读取模式),get()从缓冲区读取,rewind() 倒带(重新读取,positon=0,mark清除),

Buffer.mark()方法的作用是将当前position的值保存起来,放在mark属性中,让mark属性记住这个临时位置;

之后,可以调用Buffer.reset()方法将mark的值恢复到position中,clear( )清空缓冲区。

 

 

 通道Channel

通道可以表示一个底层的文件描述符,例如硬件设备、文件、网络连接等。FileChannel(阻塞,文件IO读写)、SocketChannel(TCP连接读写)、ServerSocketChannel(服务器监听TCP连接的通道)、DatagramChannel(UDP协议数据读写)。

获取File通道

输入输出流 -> getChannel() -> FileChannel,读取:int read(ByteBuffer buf)(写入缓冲区),(缓冲区翻转 flip)写入通道:int write(ByteBuffer buf)(读取缓冲区),关闭通道,close(),刷盘:channel.force(true)方法,强制刷新到磁盘。

高效文件复制transferFrom方法。不可以被选择器选择,没有非阻塞模式。

SocketChannel传输通道

静态方法 open() 获得 SocketChannel -> 设置为非阻塞模式 -> connect(ip,port)发起连接,判断 finishConnect() ? 是否完成连接。TCP

ServerSocketChannel通道

监听套接字的 accept()方法,来获取新连接的套接字通道:server.accept()->SocketChannel->设置非阻塞模式。read,flip,write, shutdownOutput()发送-1 终止标记,close。用Selector通道选择器判断通道何时可读。TCP

DatagramChannel数据报通道

open静态方法得 channel->channel.configureBlocking(false)方法,设置成非阻塞模式->接收数据,调用bind方法绑定数据报的监听端口channel.socket().bind() -->

读取 receive(ByteBuffer buf)-> flip() 切换读取buf -> send(buf,new Obj(ip,port))->clear切换写入buf->close关闭。UDP

Selector选择器

选择器的使命是完成IO的多路复用。一个通道代表一条连接通路,通过选择器可以同时监控多个通道的IO(输入输出)状况。选择器和通道的关系,是监控和被监控的关系。

Channel.register(Selector sel, int ops)方法将通道实例注册到一个选择器中。

监听事件

可读:SelectionKey.OP_READ,可写:SelectionKey.OP_WRITE,连接就绪(完成握手连接): SelectionKey.OP_CONNECT,接收就绪(新连接到来):SelectionKey.OP_ACCEPT

SelectableChannel可选择通道

FileChannel文件通道就不能被选择器复用,前提:判断它是否继承了抽象类SelectableChannel(可选择通道).。

SelectionKey选择键

一旦在通道中发生了某些IO事件(就绪状态达成),并且是在选择器中注册过的IO事件,就会被选择器选中,并放入SelectionKey选择键的集合中。简单地理解为:选择键,就是被选中了的IO事件。

选择器使用流程

Selector.open() 静态工厂方法 -> 实例channel.register(Selector sel, int ops)(channel必须设置非阻塞模式)

注意:一个通道,并不一定要支持所有的四种IO事件 -> 选出感兴趣的IO就绪事件, selector.select()-> 选出已经注册的、已经就绪的IO事件,

保存到SelectionKey选择键集合中 -> selector.selectedKeys() ->Set<SelectionKey  -> iterator: SelectionKey  ->IO事件对应业务处理->最后 iterator.remove当前key。

查询重载方法

select(): 阻塞调用, select(long timeout) 阻塞或指定时长,selectNow():非阻塞,不管有没有IO事件,都会立刻返回;

select() 方法返回的整数值(int整数类型),表示 2次 查询之间发生了IO事件的通道数量。

 

读书笔记

阅读: 《Netty、Redis、Zookeeper高并发实战》

 

posted @ 2020-07-30 22:35  OwenWangrq  阅读(201)  评论(0编辑  收藏  举报