NIO

同步和异步?阻塞和非阻塞?
同步和异步是针对应用程序和内核的交互而言的,同步指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪,而异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知。
阻塞和非阻塞是针对于进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,是一种读取或者写入操作函数的实现方式,阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入函数会立即返回一个状态值。
所以,IO操作可以分为3类:同步阻塞(即早期的IO操作BIO)、同步非阻塞(NIO)、异步(AIO)

NIO编程:同步非阻塞队列 ,和IO复用模型相似
channel(通道)、Buffer(缓存)、selector(选择器/IO复用器)
(TCP)ServerSocketChannel
(TCP)SocketChannel
一个有效的用户连接交给线程完成

NIO的单线程 的编程步骤
服务器Server:
1.创建ServerSocketChannel实例:ServerSocketChannel.open()
2.对实例进行绑定端口(bind(new InetSocketAddress())
3.将实例设置为非阻塞 serverSocketChannel.configureBlocking(false)
4.实例化选择器 Selector selector = Selector.open();
5.将serverSocketChannel实例注册(register)到选择器上
6.选择器进行监听,有事件发生则返回
7.遍历感兴趣事件的集合,判断是否有可接收事件发生,
8.若有可接收事件发生,获取对应通道,调用accept方法获取socketChannel实例
9.因为读写会发生阻塞,所以先将socketChannel设为非阻塞
10.将其注册到选择器,并关注读事件
11.循环进行第6步,遍历集合,判断是否有可读事件发生,
12.通过buffer从channel里读数据到byte数组里进行打印
13.关闭打开的资源,报告selector选择器、关闭socketchannel实例、
.ServerSocketChannel实例

客户端Client:

1、创建socketChanel实例
2、将socketChanel实例设置为非阻塞
3、创建selector实例
4、连接服务端,立即返回结果不成功,将chanel注册到选择器中,并关注可连接事件
5、selector实例监听事件,有事件发生则返回
6、如该事件是可连接事件,则完成当前连接(finishConnect)
7、发送消息,接收消息
8、关闭资源

NIO三大要点
channel(通道)
Buffer(缓存)
selector(选择器)

1.channel(通道):称之为通道,和IO相连,通信双方进行数据交流的通道。需要和Buffer结合使用

读数据:channel→Buffer→read
写数据: write→Buffer→channel

常用的通道:
ServerSocketChannel:监听新来的TCP连接,对每一个新用户连接会获得SocketChannel一般在服务端使用

SocketChannel:用来建立TCP连接(connect),一般在客户端使用
DatagramChannel:通过UDP读写网络中的数据,
FileChannel:用于读取、写入操作文件的通道

channel和stream的区别

  1. 方向性:channel数据是双向通信(read、write),stream是单向通信
  2. channel必须和Buffer结合使用,stream可以和Buffer结合也可以单独使用
  3. channel可以设置为阻塞和非阻塞

2.Buffer(缓存)对数据的读取写入需要使用到Buffer,Buffer的本质就是一个数组

Buffer的实现类包括:ByteBuffer、CharBuffer、IntBuffer、DoubleBuffer…

数据的标记属性:
标记、位置、限制和容量值遵守以下不变式:
0<=标记(mark)<=位置(position)<=限制(limit)<=容量(capacity)

Buffer实例的方法:
allocate(capacity)  在堆上创建指定大小的对象
allocateDirect(capacity)  在堆外空间上创建指定大小的对象
wrap(byte[])   通过存在的数组创建对象
wrap(byte[],offerset,length)   通过存在的数组创建对象

对象在堆上,ByteBuffer.allocateDirect()可以将对象创建在堆外内存里
堆外内存免除了垃圾回收过程,一旦对象创建在堆外内存,可以重复利用

方法: (在使用方法的时候着重注意读写切换!!!!)
buffer.put() 往buffer中写入数据, pos位置移动
buffer.flip() 读写模式切换 →lim指向pos,pos指向mark
buffer.get() 从Buffer中读取数据 →pos位置移动
buffer.clear() 清空Buffer缓存 mark=-1,pos=0,lim=cap=capacity

3.selector(选择器)一个选择器可以同时管理多个用户的连接,将关注的事件注册到选择器里,通过选择器来帮我们监听事件是否完成,在此期间用户可以做别的事情

selector使用步骤
1、 获取选择器的实例: Selector selector = Selector.open();
2、 将通道注册到选择器里,并确定关注的事件
先把通道设置为非阻塞:Channel.configureBlocking(false)
注册到选择器上并确定可关注事件:
Channel.register(selector,SelectionKey.OP_ACCEPT);
3、 选择器监听事件:(3种监听方法)
selector.select();通过该方法监听事件是否完成
selector.select();该方法会阻塞住,直到有感兴趣事件完成之后才会返回
selector.select(1111); 该方法在指定时间内返回,可能有事件发生,可能没有事件发生
selector.selectNow(); 不会阻塞,立马返回,可能有事件发生,可能没有事件发生,
4、 遍历感兴趣的事件集合,判断哪种事件完成
Iterator iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
5、 关闭selector资源
selector.close()
4.SelectionKey:
channel():将注册到选择器中的通道也会在SelectionKey中维护一个
Selector selector(); 将当前的选择器实例也会在SelectionKey中维护一个
boolean isValid();表示当前的SelectionKey是否是有效
void cancel();取消对当前key的关注
boolen isConnectable();//可连接事件
boolen isWritable(); //可写事件
boolen isReadable(); //可读事件
boolen isAcceptable(); //可连接事件

SelectionKey下维护的事件: 4种
OP_READ = 1 << 0; 读事件
OP_WRITE = 1 << 2; 写事件
OP_CONNECT = 1 << 3; 可连接事件
OP_ACCEPT = 1 << 4; 可接受事件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值