BIO与NIO

1.传统BIO

(1)特点

  1. 面向数据流
  2. 阻塞式传输
  3. 一个客户端对应一个线程
  4. 在客户机增多的情况下,线程资源随之增多,会造成cpu资源枯竭

(2)需求

​ 客户机向服务器输出字符串,逐一在服务器器上打印显示。类似一个简陋的聊天室功能。

(3)代码示例

  1. 服务器程序TimeServer.java

    package com.xm.bio;
    
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket; public class TimeServer { public static void main(String[] args) throws IOException {
    int port = 8080;
    if(args != null && args.length>0) {
    try {
    port = Integer.parseInt(args[0]); } catch (Exception e) { }
    } ServerSocket server = null;
    try {
    server = new ServerSocket(port);
    System.out.println("开启服务器:"+server.getLocalSocketAddress());
    Socket socket = null;
    while(true) {
    socket = server.accept();
    new Thread(new TimeServerHandle(socket)).start();
    }
    } finally {
    if(server != null) {
    System.out.println("服务器已关闭!");
    server.close();
    server = null;
    }
    } } }
  2. 服务器处理客户机进程TimeServerHandle.java

    package com.xm.bio;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.Socket;
    import java.util.Date; public class TimeServerHandle implements Runnable { private Socket socket; public TimeServerHandle(Socket socket) {
    this.socket = socket;
    } @Override
    public void run() {
    System.out.println(socket.getInetAddress().toString()+"客户机已连接");
    BufferedReader in = null;
    PrintWriter out = null;
    BufferedReader wt = null;
    try {
    in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    out = new PrintWriter(socket.getOutputStream(), true);
    wt = new BufferedReader(new InputStreamReader(System.in));
    while(true) {
    System.out.println(in.readLine());
    }
    } catch (Exception e) { } finally {
    if(in != null) {
    try {
    in.close();
    in = null;
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    if(out != null) {
    out.close();
    out = null;
    }
    if(socket != null) {
    try {
    socket.close();
    socket = null;
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } }
    } } }
  3. 客户端程序TimeClient.java

    package com.xm.bio;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.Socket;
    import java.net.UnknownHostException; public class TimeClient { public static void main(String[] args) {
    int port = 8080;
    String host = "127.0.0.1";
    Socket socket = null;
    BufferedReader in = null;
    BufferedReader wt = null;
    PrintWriter out = null;
    try {
    socket = new Socket(host, port);
    wt = new BufferedReader(new InputStreamReader(System.in));
    in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    out = new PrintWriter(socket.getOutputStream(), true);
    String body = null;
    while(true) {
    String str = wt.readLine();
    out.println(str);
    }
    } catch (UnknownHostException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }finally {
    try {
    wt.close();
    in.close();
    out.close();
    socket.close();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } } } }

2.NIO

(1)NIO特点

1.面向缓冲区

2.传输方式为管道传输

3.非阻塞

4.支持大并发下的io处理

(2)NIO下的本地文件传输

  1. 内存映射下的缓冲通道

    package com.xm.nio;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    import java.nio.file.Paths;
    import java.nio.file.StandardOpenOption;
    import java.time.Duration;
    import java.time.Instant; import org.junit.jupiter.api.Test; public class NIOFileDemo { /**
    * 1.通过流获取通道
    */
    @Test
    public void test1() {
    Instant begin = Instant.now();
    //1.定义文件流
    FileInputStream fis = null;
    FileOutputStream fos = null;
    //2.获取通道
    FileChannel inChannel = null;
    FileChannel outChannel = null;
    try {
    fis = new FileInputStream("1.jpg");
    fos = new FileOutputStream("2.jpg"); inChannel = fis.getChannel();
    outChannel = fos.getChannel(); //3.定义缓冲区
    ByteBuffer buffer = ByteBuffer.allocate(1024); //4.读取数据到缓冲区,再从缓冲区写入到文件
    while(inChannel.read(buffer) != -1) {
    //切换到读模式
    buffer.flip();
    //写操作到管道
    outChannel.write(buffer);
    //清空buffer
    buffer.clear();
    }
    } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } finally {
    //5.关闭通道和流
    if(inChannel != null) {
    try {
    inChannel.close();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    if(outChannel != null) {
    try {
    outChannel.close();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    if(fis != null) { try {
    fis.close();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } }
    if(fos != null) {
    try {
    fos.close();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } } }
    Instant end = begin.plus(Duration.ofSeconds(10));
    System.out.println("Difference in milliseconds : " + Duration.between(begin, end).toMillis());
    } /**
    * 通过文件获取管道
    */
    @Test
    public void test2() {
    Instant begin = Instant.now();
    FileChannel inChannel =null;
    FileChannel outChannel = null;
    try {
    inChannel =FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
    /**
    * StandardOpenOption.CREATE与StandardOpenOption.CREATE_NEW的区别
    * 1.StandardOpenOption.CREATE:无则创建,有则覆盖
    * 2.StandardOpenOption.CREATE_NEW:无则创建,有则报错
    */
    outChannel =FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE,StandardOpenOption.CREATE);
    //3.定义缓冲区
    ByteBuffer buffer = ByteBuffer.allocate(1024); //4.读取数据到缓冲区,再从缓冲区写入到文件
    while(inChannel.read(buffer) != -1) {
    //切换到读模式
    buffer.flip();
    //写操作到管道
    outChannel.write(buffer);
    //清空buffer
    buffer.clear();
    }
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } finally {
    //5.关闭通道和流
    if(inChannel != null) {
    try {
    inChannel.close();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    if(outChannel != null) {
    try {
    outChannel.close();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    }
    Instant end = begin.plus(Duration.ofSeconds(10));
    System.out.println("Difference in milliseconds : " + Duration.between(begin, end).toMillis()); } }
  2. 物理映射下的缓冲通道

    package com.xm.nio;
    
    import java.io.IOException;
    import java.nio.MappedByteBuffer;
    import java.nio.channels.FileChannel;
    import java.nio.channels.FileChannel.MapMode;
    import java.nio.file.Paths;
    import java.nio.file.StandardOpenOption;
    import java.time.Duration;
    import java.time.Instant; import org.junit.Test; public class NIOFileDemo2 { /**
    * 使用直接缓冲区传输
    */
    @Test
    public void test1() {
    Instant begin = Instant.now();
    FileChannel inChannel = null;
    FileChannel outChannel = null; try {
    //1.开启通道
    inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
    outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE,StandardOpenOption.CREATE,StandardOpenOption.READ); //2.定义物理缓冲区
    MappedByteBuffer inBuffer = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
    MappedByteBuffer outBuffer = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size()); //3.缓冲区读写操作
    byte[] dst = new byte[inBuffer.limit()];
    inBuffer.get(dst);
    outBuffer.put(dst); } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } finally {
    //4.关闭通道
    if(null != inChannel) { try {
    inChannel.close();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    if(null != outChannel) { try {
    outChannel.close();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    }
    Instant end = begin.plus(Duration.ofSeconds(10));
    System.out.println("Difference in milliseconds : " + Duration.between(begin, end).toMillis());
    } /**
    * 通道之间的传输
    */
    @Test
    public void test2() {
    Instant begin = Instant.now();
    FileChannel inChannel = null;
    FileChannel outChannel = null;
    //获取通道
    try {
    inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
    outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE,StandardOpenOption.CREATE); //通道间传输
    //1.to操作
    //inChannel.transferTo(0, inChannel.size(), outChannel);
    //2.from操作
    outChannel.transferFrom(inChannel, 0, inChannel.size());
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }finally {
    //4.关闭通道
    if(null != inChannel) { try {
    inChannel.close();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    if(null != outChannel) { try {
    outChannel.close();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    }
    Instant end = begin.plus(Duration.ofSeconds(10));
    System.out.println("Difference in milliseconds : " + Duration.between(begin, end).toMillis());
    } }

(3)NIO下的网络传输

  1. 阻塞式

    • 服务端程序

      package com.xm.nio.block;
      
      import java.io.IOException;
      import java.net.InetSocketAddress;
      import java.nio.ByteBuffer;
      import java.nio.channels.FileChannel;
      import java.nio.channels.ServerSocketChannel;
      import java.nio.channels.SocketChannel;
      import java.nio.file.Paths;
      import java.nio.file.StandardOpenOption;
      import java.util.Scanner; public class NIOServer { public static void main(String[] args) throws IOException { int port = 8989; //1.获取通道
      ServerSocketChannel serverChannel = ServerSocketChannel.open(); //2.绑定端口号
      serverChannel.bind(new InetSocketAddress(port)); //3.获取客户端连接
      SocketChannel socketChannel = serverChannel.accept(); //定义文件传输通道
      FileChannel outChannel = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE,StandardOpenOption.CREATE);
      ByteBuffer buffer = ByteBuffer.allocate(1024);
      while(socketChannel.read(buffer)!=-1) {
      buffer.flip();
      outChannel.write(buffer);
      buffer.clear();
      } outChannel.close();
      socketChannel.close(); } }
    • 客户端程序

      package com.xm.nio.block;
      
      import java.io.IOException;
      import java.net.InetSocketAddress;
      import java.nio.ByteBuffer;
      import java.nio.channels.FileChannel;
      import java.nio.channels.SocketChannel;
      import java.nio.file.Paths;
      import java.nio.file.StandardOpenOption; public class NIOClient { public static void main(String[] args) throws IOException {
      int port = 8989;
      //1.获取通道
      SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", port)); //2.获取文件通道
      FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
      inChannel.transferTo(0, inChannel.size(), socketChannel); //3.关闭通道
      inChannel.close();
      socketChannel.close(); } }
  2. 非阻塞式

    • 服务端程序

      package com.xm.nio.noblock;
      
      import java.io.IOException;
      import java.net.InetSocketAddress;
      import java.nio.ByteBuffer;
      import java.nio.channels.SelectionKey;
      import java.nio.channels.Selector;
      import java.nio.channels.ServerSocketChannel;
      import java.nio.channels.SocketChannel;
      import java.util.ArrayList;
      import java.util.Iterator;
      import java.util.List; public class NIOServer { public static void main(String[] args) throws IOException { int port = 8989; //1.开启通道
      ServerSocketChannel serverChannel = ServerSocketChannel.open(); //2.绑定端口号
      serverChannel.bind(new InetSocketAddress(port)); //3.设置非阻塞
      serverChannel.configureBlocking(false); //4.开启选择器
      Selector selector = Selector.open(); //5.注册连接监听
      serverChannel.register(selector, SelectionKey.OP_ACCEPT); List<SocketChannel> channels = new ArrayList<>(); while(selector.select() > 0) {
      Iterator<SelectionKey> keys = selector.selectedKeys().iterator(); while(keys.hasNext()) {
      SelectionKey key = keys.next();
      if(key.isAcceptable()) {
      SocketChannel socketChannel = serverChannel.accept();
      channels.add(socketChannel);
      System.out.println("客户端连接成功:"+socketChannel.getLocalAddress()+" hashcode:"+socketChannel.hashCode());
      socketChannel.configureBlocking(false);
      socketChannel.register(selector, SelectionKey.OP_READ);
      } else if(key.isReadable()) {
      SocketChannel socketChannel = (SocketChannel) key.channel();
      ByteBuffer dst = ByteBuffer.allocate(1024);
      int len;
      while(-1 != (len=socketChannel.read(dst))) {
      dst.flip();
      System.out.println(new String(dst.array(),0,len));
      /*for(SocketChannel sChannel:channels) {
      if(sChannel != socketChannel) {
      dst.flip();
      sChannel.write(dst);
      }
      }*/
      dst.clear();
      }
      }
      } keys.remove();
      } } }
    • 客户端

      package com.xm.nio.noblock;
      
      import java.io.IOException;
      import java.net.InetSocketAddress;
      import java.nio.ByteBuffer;
      import java.nio.channels.FileChannel;
      import java.nio.channels.SelectionKey;
      import java.nio.channels.Selector;
      import java.nio.channels.SocketChannel;
      import java.nio.file.Paths;
      import java.nio.file.StandardOpenOption;
      import java.util.Iterator;
      import java.util.Scanner; public class NIOClient{ SocketChannel socketChannel; public NIOClient() throws IOException {
      int port = 8989;
      //1.获取通道
      socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", port));
      //2.设置异步非阻塞
      socketChannel.configureBlocking(false); //2.获取文件通道
      FileChannel inChannel = FileChannel.open(Paths.get("1.md"), StandardOpenOption.READ);
      inChannel.transferTo(0, inChannel.size(), socketChannel); //3.关闭通道
      inChannel.close();
      socketChannel.close(); } public static void main(String[] args) {
      try {
      new NIOClient();
      } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      } } }

BIO与NIO的更多相关文章

  1. Java BIO、NIO、AIO 学习(转)

    转自 http://stevex.blog.51cto.com/4300375/1284437 先来个例子理解一下概念,以银行取款为例: 同步 : 自己亲自出马持银行卡到银行取钱(使用同步IO时,Ja ...

  2. BIO、NIO与NIO.2的区别与联系

    BIO.NIO.NIO.2之间的区别主要是通过同步/异步.阻塞/非阻塞来进行区分的 同步: 程序与操作系统进行交互的时候采取的是问答的形式 异步: 程序与操作系统取得连接后,操作系统会主动通知程序消息 ...

  3. Java BIO、NIO、AIO-------转载

    先来个例子理解一下概念,以银行取款为例: 同步 : 自己亲自出马持银行卡到银行取钱(使用同步IO时,Java自己处理IO读写). 异步 : 委托一小弟拿银行卡到银行取钱,然后给你(使用异步IO时,Ja ...

  4. BIO与NIO、AIO的区别

    IO的方式通常分为几种,同步阻塞的BIO.同步非阻塞的NIO.异步非阻塞的AIO. 一.BIO      在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个Serve ...

  5. JAVA中IO技术:BIO、NIO、AIO

    1.同步异步.阻塞非阻塞概念        同步和异步是针对应用程序和内核的交互而言的. 阻塞和非阻塞是针对于进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作 ...

  6. Java IO 之 BIO、NIO、AIO

    1.BIO.NIO.AIO解释 Java BIO : 同步并阻塞 (Blocking IO) 一个连接一个线程 即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不 ...

  7. Tomcat在Linux服务器上的BIO、NIO、APR模式设置

    一.BIO.NIO.AIO 先了解四个概念: 同步 : 自己亲自出马持银行卡到银行取钱(使用同步IO时,Java自己处理IO读写). 异步 : 委托一小弟拿银行卡到银行取钱,然后给你(使用异步IO时, ...

  8. tomcat并发优化之三种接收处理请求方式(BIO、NIO、APR)介绍

    原文链接:http://blog.csdn.net/xyang81/article/details/51502766 Tomcat支持三种接收请求的处理方式:BIO.NIO.APR 1>.BIO ...

  9. 操作系统层面聊聊BIO,NIO和AIO (epoll)

    BIO 有了Block的定义,就可以讨论BIO和NIO了.BIO是Blocking IO的意思.在类似于网络中进行read, write, connect一类的系统调用时会被卡住. 举个例子,当用re ...

  10. Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)

    本文会从传统的BIO到NIO再到AIO自浅至深介绍,并附上完整的代码讲解. 下面代码中会使用这样一个例子:客户端发送一段算式的字符串到服务器,服务器计算后返回结果到客户端. 代码的所有说明,都直接作为 ...

随机推荐

  1. selenium-webdriver(python) (十四) -- webdriver原理(转)

    之前看乙醇视频中提到,selenium 的ruby 实现有一个小后门,在代码中加上$DEBUG=1 ,再运行脚本的过程中,就可以看到客户端请求的信息与服务器端返回的数据:觉得这个功能很强大,可以帮助理 ...

  2. Appium自动化中截图的问题

    在用Appium做UI自动化过程中,大家会发现测试报告很重要,而在测试报告中截图很重要. 因为很多公司都是用Jenkins作为持续集成工具,所以要让执行自动化测试的人看明白自动化在跑什么,哪里失败了, ...

  3. AndroidStudio打包jar

    1.像平常一个样新建一个项目 2.(在步骤1的基础上)点击File-->New-->New Module—>选择Android Library-->点击Next(如下图:) 定 ...

  4. HTML学习之基础

    HTML是网页的标记语言不是编程语言,有一些标记段组成.大小写不敏感,可以用常用的编辑器软件编写用浏览器打开即可 有不同的版本<!DOCTYPE html> <meta charse ...

  5. jquery中beforeSend和complete的使用 --- 提高用户体验&&设置请求头

    beforeSend方法的用户主要有下面几个: 第一:用于在发送ajax请求之前设置请求头 即作为前端,如果我们希望在发送数据之前设置请求头,就可以像下面这么做: beforeSend: functi ...

  6. 【input】——数据传入后台

    1.复选框 checkbox <label class="checkbox"> <input type="checkbox" name=&qu ...

  7. idea创建Javaweb项目

    1.Javaweb项目结构 1.1修改生成.class文件的位置为WEB-INF下的classes: 生成的.class文件位置: 1.2 设置第三方jar包添加位置:

  8. Swift-取消传统For循环

    1.取消传统的For循环 传统的for,在swift 3.0 被取消 i++/++i在swift 3.0 被取消 i += 1代替 for var i = 0;i<10;i +=1 { } 2. ...

  9. Spring Bean相互依赖问题

    如果是通过get,set 注入就不会有问题 如果是通过构造函数注入,SPRING就会报循环引用注入出错 循环依赖——在采用构造器注入的方式配置bean时,很有可能会产生循环依赖的情况.比如说,一个类A ...

  10. python的变量命名及其使用

    以下内容皆从书本自学 ,归纳. 1. 变量名只能包含字母.数字和下划线.变量名可以字母或下划线打头,但不能以数字打头,例如,可将变量命名为message_1,但不能将其命名为1_message. 2. ...