一、概述
1、NIO有三大核心部分:Channel(通道),Buufer(缓存区),Selector(选择器)
- Buffer缓存区
缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了 一组方法,用来方便的访问该块内存。相比较直接对数组的操作,Buffer API更加容易操
作和管理。 - Channel通道
Java NIO的通道类似流,但又有些不同:既可以从通道中读取数据,又可以写数据到通道。但流的((input或 output)读写通常是单向的。通道可以非阻塞读取和写入通道,通道可以支持读取或写入缓冲区,也支持异步地读写。 - Selector选择器
Selector是一个ava NIO组件,可以能够检查一个或多个NIO通道,并确定哪些通道已经准备好进行读取或写 入。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接,提高效率
2、图示说明三者的关系:
- 每个channel都会对应一个Buffer 一个线程对应Selector,
- 一个Selector对应多个channel(连接)
- 程序切换到哪个channel是由事件决定的 Selector会根据不同的事件,在各个通道上切换 Buffer就是一个内存块,底层是一个数组
- 数据的读取写入是通过Buffer完成的,BIO中要么是输入流,或者是输出流,不能双向,但是NIO 的Buffer是可以读也可以写。
- Java NIO系统的核心在于:通道(Channel)和缓存区(Buffer)。通道表示打开到IO设备(例如: 文件、套接字) 的连接。若需要使用NlO系统,需要获取用于连接IO设备的通道以及用于容纳数据 的缓冲区。然后操作缓 冲区,对数据进行处理。简而言之,Channel负责传输,Buffer负责存取数 据
二、案例
1、服务器端
public class NioServer {
public static void main(String[] args) {
System.out.println("服务端启动了................");
try {
//1、获取通道
ServerSocketChannel ssc = ServerSocketChannel.open();
//2、设置非阻塞
ssc.configureBlocking(false);
//3、绑定端口
ssc.bind(new InetSocketAddress(9999));
//4、获取选择器
Selector selector = Selector.open();
//5、注册通道到选择器
ssc.register(selector, SelectionKey.OP_ACCEPT);
//6、轮询监听
while (selector.select() > 0){
//7、获取就绪的事件
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
//8、遍历
while (iterator.hasNext()){
SelectionKey selectionKey = iterator.next();
//9、判断是否可接入
if(selectionKey.isAcceptable()){
SocketChannel socketChannel = ssc.accept();
//10、设置成非阻塞通道
socketChannel.configureBlocking(false);
//11、将本客户端通道注册到选择器
socketChannel.register(selector, SelectionKey.OP_READ);
}else if (selectionKey.isReadable()){
//12、获得读key
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
//socketChannel.configureBlocking(false);
ByteBuffer bf = ByteBuffer.allocate(1024);
int len = 0;
while ((len = socketChannel.read(bf)) > 0){
bf.flip();
System.out.println(new String(bf.array(), 0, len));
//positon复位
bf.clear();
}
}
//13、处理完成,移除
iterator.remove();
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
2、客户端
public class NioClient {
public static void main(String[] args) {
System.out.println("客户端启动了................");
try {
//1、获取通道
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9999));
//2、设置非阻塞
socketChannel.configureBlocking(false);
//3、分配缓冲区
ByteBuffer bf = ByteBuffer.allocate(1024);
//4、发送数据
Scanner scanner = new Scanner(System.in);
while (true){
System.out.print("请说:");
String msg = scanner.nextLine();
bf.put(msg.getBytes());
bf.flip();
socketChannel.write(bf);
bf.clear();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
三、源码下载
https://gitee.com/charlinchenlin/store-pos