NIO学习笔记

2019/08/01

#NIO学习笔记/n## BIO 阻塞性IO

概念:客户端和服务器建立连接后,服务器会起一个线程等待客户端传输数据来,当客户端传递给服务端数据可能具有延时性,就造成了服务端线程的阻塞。在高并发的情况下,服务端会开启大量的等待线程,造成巨大压力。

  • 阻塞性I/O模型
  • 弹性伸缩能力差 (一个客户端对应一个服务端线程,线程数和客户端数是1:1的关系,机子承受不了上千万的接入)
  • 多线程耗资源

NIO

非阻塞IO

程序调用一个read方法,要么立刻返回一个错误告诉你没有数据,要么就直接返回数据,总之,调用read方法会立刻返回一个执行结果。

自己简单思考的方案:

1564601899249

实际:

1564602153613

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,实现数据块的读写

具体实现

  1. 文件类 FileChannel
  2. UDP类 DatagramChannel
  3. TCP类 ServerSocketChannel/SocketChannel

1564605520092

Buffer

  • Capacity 容量
  • Position 位置
  • Limit 上限
  • Mark 标记

1564605737695

1564605748902

1564605761676

1564605786125

1564605818342

1564605843323

selector

selector是java nio中 能检验1到多个nio通道,并且能知晓通道是否为诸如读写事件的组件,通过他一个单独的线程就可以管理多个channel

1564604682954

	selector的使用:
	1 创建selector
	2 将channel注册到selector上,监听读就绪事件
	3 阻塞等待channel有就绪事件的发生  此方法根据内部不同的操作系统底层针对IO的支持来实现的,目的是检测到注册到selector上的channel希望监听的事件是否已就绪,如果存在已就绪的,就换返回已就绪channel个数,如果没有就会一直阻塞
	4 获取就绪事件的channel集合  

SelectionKey

提供了对4种可监听事件的静态常量值:

  1. connenct 连接就绪

  2. accept 接受就绪

  3. read 读就绪

  4. write 写就绪

    Set<SelectionKey> selectedKets=selector.selectedKeys();
    

返回的这个集合可以获取到当前的channel,获取selector对象,获取事件对象就绪集合,和所关心事件集合。

NIO编程实现步骤

  1. 创建Selector
  2. 创建ServerSocketChannel,并绑定监听端口
  3. 讲channel设置为非阻塞模式
  4. 将channel注册到selector上,监听连接事件
  5. 循环调用selector的select方法,检查就绪情况
  6. 调用selectedKey方法获取就绪channel集合
  7. 判断就绪事件种类,调用业务处理方法
  8. 根据业务需要决定是否再次注册监听事件,重复执行第三步的操作

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

Post Directory