网络编程NIO:BIO和NIO详解,看不懂你打我

BIOBIO(Blocking I/O) , 同步阻塞 , 实现模式为一个连接一个线程 , 即当有客户端连接时 , 服务器端需为其单独分配一个线程 , 如果该连接不做任何操作就会造成不必要的线程开销 。 BIO是传统的java io编程 , 其相关的类和接口在java.io 包下 。
BIO适用于连接数目较小且固定的架构 , 对服务器资源的要求较高 , 是JDK1.4以前的唯一选择 , 但程序简单易理解 。
网络编程NIO:BIO和NIO详解,看不懂你打我文章插图
BIO编程流程

  1. 服务器端启动一个SeverSocket
  2. 客户端启动Socket对服务器端发起通信 , 默认情况下服务器端需为每个客户端创建一个线程与之通讯
  3. 客户端发起请求后 , 先咨询服务器端是否有线程响应 , 如果没有则会等待或被拒绝
  4. 如果有线程响应 , 客户端线程会等待请求结束后 , 再继续执行
简单代码实现//BIO-服务器端public class BIOSever {public static void main(String[] args) throws IOException {//在BIO中 , 可以使用线程池进行优化ExecutorService cachedThreadPool = Executors.newCachedThreadPool();ServerSocket serverSocket = new ServerSocket(6666);System.out.println("服务器已启动");while (true){System.out.println("等待客户端连接.....(阻塞中)");Socket socket = serverSocket.accept();System.out.println("客户端连接");cachedThreadPool.execute(new Runnable() {public void run() {handler(socket);}});}}//从客服端socket读取数据public static void handler(Socket socket){try{InputStream inputStream = socket.getInputStream();byte[] b = new byte[1024];while (true){System.out.println("等待客户端输入.....(阻塞中)");int read = inputStream.read(b);if (read != -1){System.out.println(new String(b, 0, read));}else {break;}}inputStream.close();}catch (Exception e){e.printStackTrace();}finally {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}//BIO-客户端public class BIOClient {public static void main(String[] args) throws IOException {Socket socket = new Socket("localhost", 6666);OutputStream outputStream = socket.getOutputStream();Scanner scanner = new Scanner(System.in);while (scanner.hasNextLine()){String message = scanner.nextLine();if ("exit".equals(message)) {break;}outputStream.write(message.getBytes());}outputStream.close();socket.close();}}BIO问题分析从上面代码中可以看出BIO编程的两个问题:
  1. 服务器端在监听客户端连接时(serverSocket.accept()) , 服务器端处于阻塞状态 , 不能处理其他事务
  2. 服务器端需要为每个客户端建立一个线程 , 虽然可以用线程池来优化 , 但在并发较大时 , 线程开销依旧很大
  3. 当连接的客户端没有发送数据时 , 服务器端会阻塞在read操作上 , 等待客户端输入 , 造成线程资源浪费
NIO从JDK1.4开始 , java提供了一系列改进输入/输出的新特性 , 统称为NIO , 全称n为new I/O , 是同步非阻塞的 , 所以也有人称为non-blocking I/O 。 NIO的相关类都放在java.nio包或其子包下 , 并对原先java.io包中许多类进行了改写 。
网络编程NIO:BIO和NIO详解,看不懂你打我文章插图
NIO的三大核心缓冲区(Buffer)NIO是面向缓冲区, 或者说是面向块编程的 。 在NIO的IO传输中 , 数据会先读入到缓冲区 , 当需要时再从缓冲区写出 , 这样减少了直接读写磁盘的次数 , 提高了IO传输的效率 。
缓冲区(buffer)本质上是一个可以读写数据的内存块 , 即在内存空间中预留了一定的存储空间 , 这些存储空间用来缓冲输入和输出的数据 , 这部分预留的存储空间就叫缓冲区 。
在NIO程序中 , 通道channel虽然负责数据的传输 , 但是输入和输出的数据都必须经过缓冲区buffer 。
网络编程NIO:BIO和NIO详解,看不懂你打我文章插图
在java中 , 缓冲区的相关类都在java.nio包下 , 其最顶层的类是 Buffer , 它是一个抽象类 。
Buffer类的4个重要属性:
  • mark:标记
  • position:位置 , 下一个要被读或写的元素的索引 , 每次读写缓冲区都会改变该值 , 为下次读写做准备
  • limit:表示缓冲区的终点 , 不能对缓冲区中超过极限的位置进行读写操作 , 且极限是可修改的
  • capacity:容量 , 即缓冲区的最多可容纳的数据量 , 该值在创建缓冲区时被设立 , 且不可修改
Buffer类常用方法:
网络编程NIO:BIO和NIO详解,看不懂你打我文章插图
Buffer的常用子类(它们之间最大区别在于底层实现数组的数据类型):