#NIO学习笔记/n## BIO 阻塞性IO
概念:客户端和服务器建立连接后,服务器会起一个线程等待客户端传输数据来,当客户端传递给服务端数据可能具有延时性,就造成了服务端线程的阻塞。在高并发的情况下,服务端会开启大量的等待线程,造成巨大压力。
- 阻塞性I/O模型
- 弹性伸缩能力差 (一个客户端对应一个服务端线程,线程数和客户端数是1:1的关系,机子承受不了上千万的接入)
- 多线程耗资源
NIO
非阻塞IO
程序调用一个read方法,要么立刻返回一个错误告诉你没有数据,要么就直接返回数据,总之,调用read方法会立刻返回一个执行结果。
自己简单思考的方案:
实际:
selector中注册一个连接的事件,当客户端启动向服务器端发起建立连接请求的时候,selector就会检测到这个事件,然后他会启动一个建立连接事件的处理器Acceptor Handler,并调用处理器的方法,它与客户端创建一个Socket连接,并且相应客户端建立连接成功的请求,之后Acceptor Handler会把新创建的socket连接注册到Selector中,并且注册这个连接的可读事件,到这里Acceptor Handler就完成了他的使命,注意:他不是一个线程而不是一个方法,他可以依次的处理多个请求。之后,客户端发送请求,请求还会发送到selector上,因为之前已经创建了与这个客户端建立的socket信息,并已经注册到selector上在监听他的可读事件,之后selector启动一个连接读写处理器,也是一个方法,处理刚刚客户端发过来的消息,处理完之后相应客户端请求,返回请求结果,然后这个方法会再次注册这个socket可读事件到selector上。、
由此看来:单线程的selector是一个核心,它主要接受所有的与客户端的socket连接,并且监听他们关心的事件,调用相对应的事件处理器,处理这个事件。
优点:
- 非阻塞IO
- 弹性伸缩能力强 一个线程就能处理多个请求,客户端和服务端的接入不再是bio的1:1的关系 而是1:n
- 单线程节省资源
channel 通道
- 双向性 jdk对输入输出的另一种抽象 可以类比bio中流的概念,不同的是流是单向传输,channel支持双向传输,可读可写
- 非阻塞性 可以工作在非阻塞IO中
- 操作唯一性 nio中操作channel唯一方式是操作buffer,实现数据块的读写
具体实现
- 文件类 FileChannel
- UDP类 DatagramChannel
- TCP类 ServerSocketChannel/SocketChannel
Buffer
- Capacity 容量
- Position 位置
- Limit 上限
- Mark 标记
selector
selector是java nio中 能检验1到多个nio通道,并且能知晓通道是否为诸如读写事件的组件,通过他一个单独的线程就可以管理多个channel
selector的使用:
1 创建selector
2 将channel注册到selector上,监听读就绪事件
3 阻塞等待channel有就绪事件的发生 此方法根据内部不同的操作系统底层针对IO的支持来实现的,目的是检测到注册到selector上的channel希望监听的事件是否已就绪,如果存在已就绪的,就换返回已就绪channel个数,如果没有就会一直阻塞
4 获取就绪事件的channel集合
SelectionKey
提供了对4种可监听事件的静态常量值:
-
connenct 连接就绪
-
accept 接受就绪
-
read 读就绪
-
write 写就绪
Set<SelectionKey> selectedKets=selector.selectedKeys();
返回的这个集合可以获取到当前的channel,获取selector对象,获取事件对象就绪集合,和所关心事件集合。
NIO编程实现步骤
- 创建Selector
- 创建ServerSocketChannel,并绑定监听端口
- 讲channel设置为非阻塞模式
- 将channel注册到selector上,监听连接事件
- 循环调用selector的select方法,检查就绪情况
- 调用selectedKey方法获取就绪channel集合
- 判断就绪事件种类,调用业务处理方法
- 根据业务需要决定是否再次注册监听事件,重复执行第三步的操作
NIO网络编程的缺陷
- 麻烦:NIO类库和API繁杂
- 心累:可靠性能力补齐,工作量和难度都非常大
- 有坑:Selector空轮询,导致CPU100% BUG:出现在类linux系统上,根据API的规定,如果我们在调用selector.select()方法时,如果没有准备就绪的channel 他应该阻塞在select()调用上,但Linux下的selector 一口 IO事件通知工具,操作系统使用这高性能的技术与网络协议栈异步工作,从而导致就算没有准备就绪的channel,select()方法也不会阻塞,最终造成cpu利用率100%的现象,官方声称在jdk1.6版本修复,但实际证明该问题在1.8版本仍然存在,只不过发生概率低了一些
NIO编程实战
多人聊天室
╰(*°▽°*)╯ (dadaguo-dadaguo)