NIO 同步非阻塞的编程方式
主要是解决BIO的大并发问题,NIO最重要的地方是当一个连接创建后,对应一个线程,这个连接会被注册到多路复用器上面,所以所有的连接只需要一个线程就可以完成,当这个线程中的多路复用器进行轮询的 时候,发现连接上有请求的时候,才开启线程进行处理,也就是一个请求一个线程模式。
NIO的处理方式中,当一个请求来的时候,开启线程进行处理,可能会等待后端的资源连接等等,其实该线程就被阻塞了,当并发上来的时候,还是会出现BIO一样的阻塞问题。


首先创建一个服务端的程序,客户端发起请求的时候,服务端会创建一个SocketChannel通道,客户端会和通道一一对应,然后服务端会把通道注册到多路复用器Selector上面。当多路复用器对通道进行轮询的时候,当通道需要进行操作的时候,多路复用器会通知通道去工作线程(work thread)去操作,把所有的读写数据写入Buffer缓存区中。即所有的操作都是面向Buffer实现的,而工作线程不是和客户端线程一一对应的,而是一个工作线程为多个客户端提供服务,Selector通过SocketChannel可以处理多个客户端请求。

同步非阻塞,服务器实现模式为一个请求一个通道,即客户端发送的连接请求都会注册到多路复用器上面,多路复用器轮询到有IO请求时才会启动一个线程处理。
NIO方式适用于连接数目多,且连接比较短(轻操作)的架构,比如聊天服务器。

Buffer:ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer
Channel:SocketChannel、serverSocketChannel
Selector:Selector、AbstractSelector
SelectionKey: OP_ACCEPT :连接成功的标记
OP_READ :可以读取数据的标记
OP_WRITE :可以写入数据的标记
OP_CONNECT :建立连接后的标记

  • Buffer缓存区不是代表一个Buffer,它可以是一个或者多个Buffer。
package nio;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Scanner;public class NIOClient {public static void main(String[] args){// 创建远程连接地址InetSocketAddress remote = new InetSocketAddress("localhost",9999);SocketChannel channel = null;ByteBuffer buffer = ByteBuffer.allocate(1024);try {channel = SocketChannel.open();channel.connect(remote);Scanner reader = new Scanner(System.in);while (true){System.out.println("put message for send to Server >");String line = reader.nextLine();if(line.equals("exit")){break;}buffer.put(line.getBytes("UTF-8"));buffer.flip();channel.write(buffer);buffer.clear();int readLength = channel.read(buffer);if(readLength == -1){break;}// 重置缓存游标buffer.flip();byte[] datas = new byte[buffer.remaining()];// 读取数据到数组buffer.get(datas);System.out.println("from server : " + new String(datas, "UTF-8"));// 清空缓存buffer.clear();}}catch (Exception e){e.printStackTrace();}finally {if(channel != null){try {channel.close();}catch (IOException e){e.printStackTrace();}}}}
}
package nio;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.*;
import java.nio.channels.*;
import java.nio.channels.spi.AbstractSelector;
import java.util.Iterator;
import java.util.Scanner;public class NIOServer implements Runnable {// 多路复用器,选择器。用于注册通道private Selector selector;// 定义两个缓存 分别用于读和写;初始化空间大小为1024字节private ByteBuffer readBuffer = ByteBuffer.allocate(1024);private ByteBuffer writeBuffer = ByteBuffer.allocate(1024);public static void main(String[] args){new Thread(new NIOServer(9999)).start();}public NIOServer (int port){init(port);}private void init(int port) {try {System.out.println("server starting at port " + port + "...");this.selector = Selector.open();// 开启服务通道ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 非阻塞,传递参数为true为阻塞模式serverSocketChannel.configureBlocking(false);// 绑定端口serverSocketChannel.bind(new InetSocketAddress(port));// 注册,并标记当前服务通道状态/*** register(Selector,int)* int  - 状态编码* OP_ACCEPT :连接成功的标记* OP_READ :可以读取数据的标记* OP_WRITE :可以写入数据的标记* OP_CONNECT :建立连接后的标记*/serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);System.out.println("server start");}catch (IOException e){e.printStackTrace();}}@Overridepublic void run() {while (true){try {// 阻塞方法,当至少一个通道被选中,此方法返回。this.selector.select();// 返回以选中的通道标记集合,集合保存的是通道的标记,相当于是通道的IDIterator<SelectionKey> keys = this.selector.selectedKeys().iterator();while (keys.hasNext()){SelectionKey key = keys.next();// 将本次要处理的通道冲集合中删除,下次删除根据新的通道列表再次执行必要的业务逻辑keys.remove();// 通道是否有效if(key.isValid()){try {if (key.isAcceptable()){accept(key);}}catch (CancelledKeyException e){key.cancel();}try{if(key.isReadable()){read(key);}}catch (CancelledKeyException cke){key.cancel();}try{if(key.isWritable()){write(key);}}catch (CancelledKeyException cke){key.cancel();}}}} catch (IOException e) {e.printStackTrace();}}}private void write(SelectionKey key){this.writeBuffer.clear();SocketChannel channel = (SocketChannel)key.channel();Scanner reader = new Scanner(System.in);try {System.out.println("put message for send to client > ");String line = reader.nextLine();writeBuffer.put(line.getBytes("UTF-8"));writeBuffer.flip();channel.write(writeBuffer);channel.register(this.selector,SelectionKey.OP_READ);}catch (IOException e){e.printStackTrace();}}private void read(SelectionKey key){try {// 清空读缓存this.readBuffer.clear();// 获取通道SocketChannel channel = (SocketChannel)key.channel();// 将通道中的数据读到缓存中。通道中的数据,就是客户端发送给服务器的数据。int readLength = channel.read(readBuffer);// 检查客户端是否写入数据if(readLength == -1){// 通道关闭key.channel().close();// 关闭连接key.cancel();return;}// flip,NIO中最复杂的操作就是Buffer的控制/** Buffer中有一个游标。游标的信息在操作后不会归零,如果直接访问Buffer的话,数据有可能不一致。* flip是重置游标的方法.NIO编程中,flip方法是常用的方法**/this.readBuffer.flip();// 字节数据,保存具体数据。Buffer.remaining() ->获取Buffer中有效数据长度的方法。byte[] datas = new byte[readBuffer.remaining()];// 是将Buffer中的有效数据保存到有效数组中。readBuffer.get(datas);System.out.println("from" + channel.getRemoteAddress() + " client : " + new String(datas,"UTF-8"));channel.register(this.selector,SelectionKey.OP_WRITE);}catch (IOException e){e.printStackTrace();}}private void accept(SelectionKey key){try {// 此通道为init方法中注册到Seleor上的ServerSocketChannelServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();// 阻塞方法,当客户端发起请求后返回.此通道和客户端一一对应SocketChannel channel = serverSocketChannel.accept();channel.configureBlocking(false);// 设置对用客户端的通道标记状态,此通道为读取数据使用的。channel.register(this.selector,SelectionKey.OP_READ);}catch (IOException e){e.printStackTrace();}}
}


Buffer的应用固定逻辑

  • 写操作逻辑
  • 1.clear()
  • 2.put()
  • 3.flip()
  • 4.socketChanel.write(buffer); ->将缓存数据发送到网络的另一端
  • 5.clear()
  • 读操作逻辑
  • 1.clear()
  • 2.SocketChannel.read(buffer); ->从网络中读取数据
  • 3.buffer.flip()
  • 4.buffer.get()
  • 5.buffer.clear()

Java NIO编程相关推荐

  1. Java NIO编程的技巧和陷阱

    去年做的分享,一直上传slideshare失败,今天又试了下,成功了.这个主题主要介绍Java NIO编程的技巧和陷阱,解读了一些NIO框架的源码,以及编写高性能NIO网络框架所需要注意的技巧和缺陷. ...

  2. JAVA NIO编程入门(二)

    一.回顾 上一篇文章 JAVA NIO编程入门(一)我们学习了NIO编程的基础知识,并通过一个小demo实战帮助了解NIO编程的channel,buffer等概念.本文会继续学习JAVA NIO编程, ...

  3. Java NIO编程基础

    Java NIO编程基础 Java NIO 基本介绍 NIO的Buffer基本使用 NIO 和 BIO 的比较 NIO 三大核心原理示意图 缓冲区(Buffer) 基本介绍 Buffer 类及其子类 ...

  4. Java NIO 编程:Buffer、Channel、Selector原理详解

    1 Java 中的 I/O模型:BIO.NIO.AIO 1.1 BIO.NIO.AIO概念介绍 I/O 模型简单的理解:就是 用什么样的通道进行数据的发送和接收,很大程度上决定了程序通信的性能. Ja ...

  5. 第3章-Java NIO编程

    目录 1.Java NIO基本介绍 2.NIO和BIO的比较 3.NIO三大核心原理示意图 Selector.Channel和Buffer的关系图 关系图的说明 4.缓冲区(Buffer) 基本介绍 ...

  6. 三、Java NIO 编程

    3.1.Java NIO 基本介绍 Java NIO 全称java non-blocking IO,是指JDK提供的新API.从JDK1.4开始,Java提供了一系列改进的输入/输出的新特性,被统称为 ...

  7. NIO详解(一):java网络编程IO总结(BIO、NIO、AIO)

    1.基本概念 在Java网络通信中,最基本的概念就是Socket编程了.Socket又称"套接字" 向网络发出请求或者应答网络请求. Socket 和ServerSocket类库位 ...

  8. java nio 客户端_Java网络编程:Netty框架学习(二)---Java NIO,实现简单的服务端客户端消息传输...

    概述 上篇中已经讲到Java中的NIO类库,Java中也称New IO,类库的目标就是要让Java支持非阻塞IO,基于这个原因,更多的人喜欢称Java NIO为非阻塞IO(Non-Block IO), ...

  9. Java网络编程与NIO学习总结

    #Java网络编程与NIO学习总结 这篇总结主要是基于我之前Java网络编程与NIO系列文章而形成的的.主要是把重要的知识点用自己的话说了一遍,可能会有一些错误,还望见谅和指点.谢谢 #更多详细内容可 ...

最新文章

  1. 人工智阅读理解能力首超人类,阿里巴巴刷新世界纪录
  2. android studio中error,ERROR在Android Studio中
  3. C语言之去掉https链接的默认443端口
  4. Objective-C 2.0 with Cocoa Foundation 1 前言
  5. 记一次 React 组件无法更新状态值的问题分析与解决
  6. 剑指Offer之逆序对问题
  7. django.db.utils.OperationalError: (1050, “Table ‘表名‘ already exists)解决方法
  8. MySQL5.7 踩坑实录
  9. 学校管理 学生会管理系统(SSM)vue+ssm+shiro
  10. vuxui 安装使用,解决npm项目文件严重问题提示
  11. Deeping Learning学习与感悟——《深度学习工程师》_5
  12. 一个漂亮的电子数字字体分享electronicFont
  13. 数据的存储和管理,主要有哪些好的方法?
  14. npm install 时报错:npm WARN vueproject@1.0.0 No repository field.(缺少repository字段)
  15. MySQL的集合运算
  16. 爬虫用fiddler抓取网易新闻客户端手机app内容
  17. 【实时渲染】实时渲染中的光与颜色
  18. Titanic 泰坦尼克数据集 特征工程 机器学习建模
  19. Linux下批处理文件编写
  20. Windows7只能设置纯色背景解决方法

热门文章

  1. AD18.1.9和AD18.1.7的安装步骤
  2. V90 PN 伺服驱动器的一键自动优化功能_方法示例
  3. 【强化学习论文合集】三十四.2021机器人与自动化国际会议论文(ICRA2021)
  4. 杠上植物大战僵尸210331
  5. el-table样式总结—持续更新
  6. 用计算机计算四下教案,四年级数学教案——“认识计算器 ”教学设计
  7. Struts中ActionForm的生命周期
  8. 噪声调幅干扰信号Python实现
  9. python读取odb_Python提取Abaqus ODB中的场变量(Field output)与历史变量(History output)方法...
  10. java文件切割_Java实现文件切割拼接的实现代码