NIO之NIO介绍

旧城等待, 2023-03-02 10:26 58阅读 0赞

BIO

  1. 在介绍NIO之前,我们来了解一下BIO以及为什么会出现NIO。下面来见一段传统的BIO形式的代码。

Server

  1. ServerSocket server = new ServerSocket();
  2. server.bind(new InetSocketAddress(9876));
  3. while(true) {
  4. System.out.println("等待连接");
  5. //阻塞接收
  6. //程序释放CPU资源
  7. Socket accept = server.accept(); //mark1
  8. System.out.println("连接成功");
  9. //读数据
  10. byte[] buff = new byte[1024];
  11. int pos = accept.getInputStream().read(buff); //mark2
  12. String content = new String(buff);
  13. System.out.println("读出数据:" + content);
  14. //写数据
  15. accept.getOutputStream().write("服务器返回数据".getBytes());
  16. System.out.println("数据返回成功");
  17. }

Client

  1. Socket socket = new Socket();
  2. socket.connect(new InetSocketAddress("127.0.0.1", 9876));
  3. Scanner sc = new Scanner(System.in);
  4. System.out.println("请输入内容");
  5. while(true) {
  6. String next = sc.next();
  7. socket.getOutputStream().write(next.getBytes());
  8. }
  9. 代码很简单,非常常见的服务端客户端通信。那么在这段代码中,服务端有两个地方会阻塞,分别为mark1mark2所标记的代码处。
  10. 运行Server,程序阻塞在mark1处等待客户连接,此时启动ClientServer端将运行至mark2处阻塞等待Client传输数据,Client传输数据后,Server结束一次while循环。这是我们最开始传统的运行方式,这样的形式我Server端同时只能处理一个Client的请求(因为mark1处被阻塞了),如果想处理多个在BIO的模式下只能开多线程处理。
  11. BIO的模式下多线程能同时处理多个客户端请求吗,答案是肯定的。但是会有什么问题:
  • 多线程上下文切换的消耗
  • 服务器开线程数量的限制

    很明显会带来上述几个问题,那么我们能不能用单线程来处理多个客户端呢?单线程同时处理多个客户端请求我们要处理什么问题?

NIO

  1. 能否以单线程处理多个客户端呢?答案是肯定的,我们只要处理两个问题,第一,将上述案例中的mark1变为非阻塞,第二,将mark2变为非阻塞形式,来看一段伪代码。
  2. Set<Socket> set = new HashSet<>();
  3. ServerSocket server = new ServerSocket();
  4. server.bind(new InetSocketAddress(9876));
  5. while(true) {
  6. setServerSocketNoBlock(server); //假设存在使得ServerSocket变为非阻塞的方法
  7. Socket accept = server.accept();
  8. if accept == null { //handle1
  9. //是否有客户端发送数据
  10. if yes {
  11. for set {
  12. accept.read(buff);
  13. }
  14. }
  15. //continue
  16. } else { //handle2
  17. setSocketNoBlock(accept); //假设存在使得Socket变为非阻塞的方法
  18. set.add(accept);
  19. for set {
  20. accept.read(buff);
  21. }
  22. //continue
  23. }
  24. }
  25. 在上述代码中我们将原来的mark1mark2都变为非阻塞的形式,这样回发生什么,我们分析一下。Server端进入while循环,此时没有客户端连接accept null,没有客户端发送数据,程序进入handle1后进入下一次循环。一旦有客户端连接上来,假设此时A客户端连接上来但是不发送数据,程序进入handle2处理后进入下一次循环,此时B客户端连接上来,程序进入handle2后进入下一次循环,此时A客户端发送了一条数据消息,程序进入handle1并且接收到了A客户端的消息之后进入下一次循环。这样的形式就实现了我们单线程来处理多个客户端的需求。
  26. 那么上述伪代码中的最重要的地方其实是两处非阻塞的代码,从JDK1.4开始,jdk官方给我们提供了ServerSocketChannel以及SocketChannel这两个类来代替我们原来的ServerSocketSocket,查看其API可以发现configureBlocking函数,看其注释可知,这个方法就能实现非阻塞的模式,那么我们上述的伪代码即可实现。NIO大致原理就是这样,其中NIO还有几个比较重要的概念buffchannelselector,我们后续博客会简单分析一下。
  27. /** * Adjusts this channel's blocking mode. * * <p> If the given blocking mode is different from the current blocking * mode then this method invokes the {@link #implConfigureBlocking * implConfigureBlocking} method, while holding the appropriate locks, in * order to change the mode. </p> */
  28. public final SelectableChannel configureBlocking(boolean block)
  29. throws IOException
  30. {
  31. synchronized (regLock) {
  32. if (!isOpen())
  33. throw new ClosedChannelException();
  34. if (blocking == block)
  35. return this;
  36. if (block && haveValidKeys())
  37. throw new IllegalBlockingModeException();
  38. implConfigureBlocking(block);
  39. blocking = block;
  40. }
  41. return this;
  42. }

发表评论

表情:
评论列表 (有 0 条评论,58人围观)

还没有评论,来说两句吧...

相关阅读

    相关 NIO简单介绍

    一、什么是NIO 1、Java NIO全称java non-blocking IO, 是指JDK提供的新API。从JDK1.4开始,Java提供了一系列改进的输入/输出的

    相关 1、NIO详解标准NIO

    前言   NIO即新的输入输出,这个库是在JDK1.4中才引入的。它在标准java代码中提供了高速的面向块的IO操作。NIO即New IO,NIO和IO有相同的作用和目的

    相关 NIONIO、AIO

    基础概念 `BIO`:同步阻塞式IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程