NIO与Netty-2-BIO非阻塞改造

NIO与Netty-2-BIO非阻塞改造

  • 因为BIO是阻塞式IO,单线程情况下处理者线程可能阻塞在其中一个连接套接字的read或服务套接字的accept上,因此只能是针对每一个套接字,都新建一个线程处理其数据读取。

  • 改造前BIO的模型

    • 一个监听线程,多少连接就存在多少个连接线程。一个线程对应一个socket。
    • 在这里插入图片描述
  • 利用超时返回来改造

    • 因为ServerSocket的accpet和连接socket的read有超时返回功能,可以利用此来进行(伪)非阻塞改造。

    • 改造思路

      • 只使用一个线程,在创建ServerSocket和Socket时设置上较短的超时时间,使得原本无数据就阻塞的accept和read都可以在超时时停止阻塞向下运行。

      • 然后在死循环中先尝试accpet获取连接,再去挨个对建立的连接尝试进行read操作。

      • 在这里插入图片描述

      • 改造后的server

        • public static void main(String[] args) throws Exception {
              byte[] msg=new byte[1024];//存储收到信息用的数组
          	//存储建立好的连接和其输入流的map
              Map<Socket,InputStream> map=new HashMap<>();
              //建立serversocket,并设置超时时间,防止一直阻塞
              ServerSocket serverSocket = new ServerSocket(6666);
              serverSocket.setSoTimeout(1);
              System.out.println("服务器启动了");
              while (true) {//一直轮询
                  try{
                      //accept若超时未获得新连接会抛出异常
                      Socket socket = serverSocket.accept();
                      System.out.println("连接到一个客户端");
                      socket.setSoTimeout(1);//设置超时时间
                      map.put(socket,socket.getInputStream());
                  }catch (SocketTimeoutException e){
                      //捕获超时异常不处理
                  }
                  //将当前map的key拷贝下来
                  Set<Socket> clientSockets = new HashSet<>(map.keySet());
                  for(Socket socket1:clientSockets){//遍历已经建立的连接
                      try{
                          //read若超时未读到信息则抛出异常
                          int i = map.get(socket1).read(msg);
                          if(i>0){//存在信息则
                              System.out.println("收到信息:"+
                                                 new String(msg).substring(0,i));
                          }else {
                              map.get(socket1).close();
                              socket1.close();
                              map.remove(socket1);
                          }
                      }catch (SocketTimeoutException e){}
                      catch (SocketException e){
                          map.get(socket1).close();
                          socket1.close();
                          map.remove(socket1);
                      }
                  }
              }
          }
        • 此时我们的server只有一个线程,它可以处理多个socket。

发布了27 篇原创文章 · 获赞 1 · 访问量 894

猜你喜欢

转载自blog.csdn.net/hu853996234/article/details/104253687
今日推荐