NIO是JDK 1.4 开始有的,其目的是为了提高速度。NIO翻译成no-blocking io。
传统IO是⼀次⼀个字节地处理数据,NIO是以块(缓冲区)的形式处理数据。最主要的是,NIO可以实现
非阻塞,而传统IO只能是阻塞的。
IO的实际场景是文件IO和网络IO,NIO在网络络IO场景下提升就尤其明显了。
在Java NIO有三个核心部分组成。分别是Buffer(缓冲区)、Channel(管道)以及Selector(选择器)
候选者:可以简单的理解为:Buffer是存储数据的地方,Channel是运输数据的载体,而Selector用于检查多个
Channel的状态变更情况
public class NoBlockServer {public static void main(String[] args) throws IOException {// 1.获取通道ServerSocketChannel server = ServerSocketChannel.open();// 2.切换成⾮阻塞模式server.configureBlocking(false);// 3. 绑定连接server.bind(new InetSocketAddress(6666));// 4. 获取选择器Selector selector = Selector.open();// 4.1将通道注册到选择器上,指定接收“监听通道”事件server.register(selector, SelectionKey.OP_ACCEPT);// 5. 轮训地获取选择器上已“就绪”的事件--->只要select()>0,说明已就绪while (selector.select() > 0) {// 6. 获取当前选择器所有注册的“选择键”(已就绪的监听事件)Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();// 7. 获取已“就绪”的事件,(不同的事件做不同的事)while (iterator.hasNext()) {SelectionKey selectionKey = iterator.next();// 接收事件就绪if (selectionKey.isAcceptable()) {// 8. 获取客户端的链接SocketChannel client = server.accept();// 8.1 切换成⾮阻塞状态client.configureBlocking(false);// 8.2 注册到选择器上-->拿到客户端的连接为了读取通道的数据(监听读就绪事件)client.register(selector, SelectionKey.OP_READ);} else if (selectionKey.isReadable()) { // 读事件就绪// 9. 获取当前选择器读就绪状态的通道SocketChannel client = (SocketChannel) selectionKey.channel();// 9.1读取数据ByteBuffer buffer = ByteBuffer.allocate(1024);// 9.2得到⽂件通道,将客户端传递过来的图⽚写到本地项⽬下(写模式、没有则创建)FileChannel outChannel = FileChannel.open(Paths.get("2.png"),StandardOpenOption.WRITE, StandardOpenOption.CREATE);while (client.read(buffer) > 0) {// 在读之前都要切换成读模式buffer.flip();outChannel.write(buffer);// 读完切换成写模式,能让管道继续读取⽂件的数据buffer.clear();}}// 10. 取消选择键(已经处理过的事件,就应该取消掉了)iterator.remove();}}}}
public class NoBlockClient {public static void main(String[] args) throws IOException {// 1. 获取通道SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 6666));// 1.1切换成⾮阻塞模式socketChannel.configureBlocking(false);// 1.2获取选择器Selector selector = Selector.open();// 1.3将通道注册到选择器中,获取服务端返回的数据socketChannel.register(selector, SelectionKey.OP_READ);// 2. 发送⼀张图⽚给服务端吧FileChannel fileChannel =FileChannel.open(Paths.get("X:\\Users\\ozc\\Desktop\\⾯试造⽕箭\\1.png"), StandardOpenOption.READ);// 3.要使⽤NIO,有了Channel,就必然要有Buffer,Buffer是与数据打交道的呢ByteBuffer buffer = ByteBuffer.allocate(1024);// 4.读取本地⽂件(图⽚),发送到服务器while (fileChannel.read(buffer) != -1) {// 在读之前都要切换成读模式buffer.flip();socketChannel.write(buffer);// 读完切换成写模式,能让管道继续读取⽂件的数据buffer.clear();}// 5. 轮训地获取选择器上已“就绪”的事件--->只要select()>0,说明已就绪while (selector.select() > 0) {// 6. 获取当前选择器所有注册的“选择键”(已就绪的监听事件)Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();// 7. 获取已“就绪”的事件,(不同的事件做不同的事)while (iterator.hasNext()) {SelectionKey selectionKey = iterator.next();// 8. 读事件就绪if (selectionKey.isReadable()) {// 8.1得到对应的通道SocketChannel channel = (SocketChannel) selectionKey.channel();ByteBuffer responseBuffer = ByteBuffer.allocate(1024);// 9. 知道服务端要返回响应的数据给客户端,客户端在这⾥接收int readBytes = channel.read(responseBuffer);if (readBytes > 0) {// 切换读模式responseBuffer.flip();System.out.println(new String(responseBuffer.array(), 0, readBytes));}}// 10. 取消选择键(已经处理过的事件,就应该取消掉了)iterator.remove();}}}}
