Nio入门学习

1. Nio入门学习

  1. Nio概述

    • JDK 1.4中的java.nio.*包中引入新的Java I/O库,其目的是提高速度。实际上,“旧”的I/O包已经使用NIO重新实现过,即使我们不显式的使用NIO编程,也能从中受益

    • 可以认为传统IO是面向字节流的,Nio是面向块的

    • Nio四个核心组件

      [外链图片转存失败(img-nhe35745-1564585670321)(C:\Users\xy\AppData\Roaming\Typora\typora-user-images\1562933159797.png)]

      1. Buffer

        • 存放读写的数据
      2. Channel

        • 各种各样的channel代表着实体之间的连接,通过它能够执行IO操作
      3. Selector and SelectionKey

        • 与selectable channel一起组成了多路复用,非阻塞的IO的功能
      4. Charset

        • Charset与他们相关编解码器(decoder and encoder)一起可以完成字节(byte)与Unicode字符之间的转换
  2. Nio API初试,比较Nio与传统IO之间文件的复制速率

    Bio文件复制

    public class BioFileCopy implements FileCopy {
    
        @Override
        public void fileCopy(String source, String dest) {
            BufferedInputStream bufferedInputStream = null;
            BufferedOutputStream bufferedOutputStream = null;
            try {
                bufferedInputStream = new BufferedInputStream(new FileInputStream(source));
                bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(dest));
                byte[] bytes = new byte[1024];
                int len = -1;
                while ((len = bufferedInputStream.read(bytes)) != -1) {
                    bufferedOutputStream.write(bytes,0,len);
                }
            } catch (IOException e) {
                e.printStackTrace();
                System.err.println("file copy fail!");
            } finally {
                    try {
                        if (null != bufferedInputStream) {
                            bufferedInputStream.close();
                        }
                        if (null != bufferedOutputStream) {
                            bufferedOutputStream.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
            }
        }
    
    }
    

    Nio文件复制

    public class NioFileCopy implements FileCopy {
    
        @Override
        public void fileCopy(String source, String dest) {
            FileChannel inChannel = null;
            FileChannel outChannel = null;
            try {
                FileInputStream fileInputStream = new FileInputStream(source);
                FileOutputStream fileOutputStream = new FileOutputStream(dest);
                inChannel = fileInputStream.getChannel();
                outChannel = fileOutputStream.getChannel();
                // allocate the ByteBuffer
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                int len = -1;
                while ((len = inChannel.read(byteBuffer)) != -1) {
                    byteBuffer.flip();
                    outChannel.write(byteBuffer);
                    byteBuffer.clear();
                }
            } catch (IOException e) {
                e.printStackTrace();
                System.err.println("file copy fail!");
            } finally {
                try {
                    if (null != inChannel) {
                        inChannel.close();
                    }
                    if (null != outChannel) {
                        outChannel.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
    }
    

    测试代码:

    public class FileCopyComparationTest {
    
        /**
         * 210 MB
         */
        private final String sourceFile = "C:\\Users\\xy\\Downloads\\mall-server.zip";
    
        private final String bioDestFile = "C:\\Users\\xy\\Desktop\\bioFileCopy.zip";
    
        private final String nioDestFile = "C:\\Users\\xy\\Desktop\\nioFileCopy.zip";
    
        /**
         * the bio version
         */
        private final FileCopy bioFileCopy = new BioFileCopy();
    
        /**
         * the nio version
         */
        private final FileCopy nioFileCopy = new NioFileCopy();
    
    
        @Test
        public void test() {
            long star1 = System.currentTimeMillis();
            bioFileCopy.fileCopy(sourceFile,bioDestFile);
            System.out.println("Bio cost:"+(System.currentTimeMillis()-star1)+"ms!");
    
            long start2 = System.currentTimeMillis();
            nioFileCopy.fileCopy(sourceFile,nioDestFile);
            System.out.println("Nio cost:"+(System.currentTimeMillis()-start2)+"ms!");
        }
    
    }
    
  3. Buffer缓冲区

    1. 四大标志位:position,limit,mark,capacity

      示例代码:

      public class BufferFlagTest {
      
          @Test
          public void test() throws Exception {
              final int capacity = 1024;
              // allocate a ByteBuffer
              ByteBuffer byteBuffer = ByteBuffer.allocate(capacity);
              System.out.println("before put:");
              System.out.println("position:"+byteBuffer.position()); // 0
              System.out.println("limit:"+byteBuffer.limit()); // 1024
              System.out.println("mark:"+byteBuffer.mark()); 
              System.out.println("capacity:"+byteBuffer.capacity()); // 1024
              System.out.println("--------------------------");
      
              String data = "夏齐";
              // put the data into the buffer
              byteBuffer.put(data.getBytes("UTF-8"));
              System.out.println("after put:");
              System.out.println("position:"+byteBuffer.position()); //6
              System.out.println("limit:"+byteBuffer.limit());    // 1024
              System.out.println("mark:"+byteBuffer.mark());  
              System.out.println("capacity:"+byteBuffer.capacity()); // 1024
              System.out.println("--------------------------");
      
              byteBuffer.flip();
              System.out.println("after filp:");
              System.out.println("position:"+byteBuffer.position()); // 0
              System.out.println("limit:"+byteBuffer.limit());    // 6
              System.out.println("mark:"+byteBuffer.mark());  
              System.out.println("capacity:"+byteBuffer.capacity()); // 1024
              System.out.println("--------------------------");
      
              byteBuffer.clear();
              System.out.println("after clear:");
              System.out.println("position:"+byteBuffer.position()); // 0
              System.out.println("limit:"+byteBuffer.limit());    // 1024
              System.out.println("mark:"+byteBuffer.mark());  
              System.out.println("capacity:"+byteBuffer.capacity()); // 1024
          }
      
      }
      
    2. 标志位变化图解

      在这里插入图片描述

    3. Memory Mapped File实现文件复制

      public class MemoryMappedFileTest {
      
          public static void main(String[] args) {
              FileChannel inChannel = null;
              FileChannel outChannel = null;
              File src = new File("C:\\Users\\xy\\Desktop\\TODO.txt");
              String dest = "C:\\Users\\xy\\Desktop\\TODO2.txt";
              try {
                  FileInputStream fileInputStream = new FileInputStream(src);
      
                  // retrieve the channel
                  inChannel = fileInputStream.getChannel();
                  outChannel = FileChannel.open(Paths.get(dest), StandardOpenOption.CREATE_NEW,StandardOpenOption.WRITE,StandardOpenOption.READ);
      
                  // MMF,memory mapped file
                  MappedByteBuffer inMapBuf = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
                  MappedByteBuffer outMapBuf = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
      
                  // file copy
                  byte[] bytes = new byte[inMapBuf.capacity()];
                  inMapBuf.get(bytes);
                  outMapBuf.put(bytes);
              } catch (IOException e) {
                  e.printStackTrace();
                  System.err.println("fail!");
              } finally {
                  try {
                      if (null != inChannel) {
                          inChannel.close();
                      }
                      if (null != outChannel) {
                          outChannel.close();
                      }
                  }catch (IOException e) {
                      e.printStackTrace();
                  }
                  System.out.println("finish!");
              }
          }
      }
      
    4. 直接(Direct)缓冲区与非直接缓冲区

      1. 直接缓冲区

      [外链图片转存失败(img-ptrAeiEl-1564585670325)(C:\My Desktop File\self learning notes\network programming\directBuffer.png)]

      1. 非直接缓冲区

        [外链图片转存失败(img-ISpyOunw-1564585670326)(C:\My Desktop File\self learning notes\network programming\nonDirectBuffer.png)]

      2. 区别

        直接缓冲区本质上减少了一次将数据从用户地址空间复制到内核地址空间的时间,加快的IO速度,但进行分配比非直接缓冲区要慢。

    5. Nio网络通信

      [外链图片转存失败(img-2aCKaVzg-1564585670327)(C:\My Desktop File\self learning notes\network programming\nio网络通信.png)]

      1. 概述

        我们通常使用NIO是在网络中使用的,网上大部分讨论NIO都是在网络通信的基础之上的!说NIO是非阻塞的NIO也是网络中体现的!

        从上面的图我们可以发现还有一个Selector选择器。从一开始我们就说过了,nio的核心要素有:

        • Buffer缓冲区

        • Channel通道

        • Selector选择器

        我们在网络中使用NIO往往是I/O模型的多路复用模型

        • Selector选择器就可以比喻成麦当劳的广播

        • 一个线程能够管理多个Channel的状态

      2. Nio阻塞通信,即没有Selector

        测试代码:

        Server:

        public class BlockingServer {
        
            private static final int port = 45000;
        
            private static final ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        
            public static void main(String[] args) throws IOException {
                // create the ServerSocketChannel
                ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        
                // bind the ip address and port
                serverSocketChannel.socket().bind(new InetSocketAddress(port));
        
                System.out.println("Server start at "+new Date());
                while (true) {
                    // listening the client connection
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    System.out.println("establish connection:"+serverSocketChannel);
        
                    // clear the buffer
                    byteBuffer.clear();
        
                    // read the data of client
                    int read = socketChannel.read(byteBuffer);
                    byteBuffer.flip();
        
                    // retrieve the client message
                    String cliMsg = null;
                    System.out.println((cliMsg = new String(byteBuffer.array(),0,read,"UTF-8")));
        
                    // construct the response message
                    byteBuffer.clear();
                    byteBuffer.put(("hello,"+cliMsg).getBytes("UTF-8"));
        
                    // send to the client
                    byteBuffer.flip();
                    socketChannel.write(byteBuffer);
        
                    //close the connection
                    socketChannel.close();
        
                    break;
                }
                serverSocketChannel.close();
                System.out.println("Server stop..");
            }
        }
        

        Client:

        public class BlockingClient {
        
            private static final InetSocketAddress SOCKET_ADDRESS = new InetSocketAddress("127.0.0.1", 45000);
        
            private static final ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        
            public static void main(String[] args) throws IOException {
        
                // create the SocketChannel
                SocketChannel socketChannel = SocketChannel.open();
        
                // connect the server
                socketChannel.socket().connect(SOCKET_ADDRESS);
        
                // construct message
                String msg = "夏齐";
                byteBuffer.put(msg.getBytes("UTF-8"));
                byteBuffer.flip();
        
                // send message
                socketChannel.write(byteBuffer);
                byteBuffer.clear();
        
                // read the response message
                int read = socketChannel.read(byteBuffer);
                System.out.println(new String(byteBuffer.array(),0,read));
                socketChannel.close();
            }
        }
        
      3. 非阻塞通信

        Server:

        public class NonBlockingServer {
        
            private static final int port = 45000;
        
            private static final ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        
            public static void main(String[] args) throws IOException {
                // create the ServerSocketChannel
                ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        
                // bind the ip address and listening port
                serverSocketChannel.socket().bind(new InetSocketAddress(port));
        
                // config the channel to non-blocking
                serverSocketChannel.configureBlocking(false);
        
                System.out.println("Server start");
        
                while (true) {
                    SocketChannel socketChannel = null;
                    // if no client connects,it will return null,rather than waiting the client to connect
                    while ((socketChannel = serverSocketChannel.accept()) == null) {
                        System.out.println("no client connect,I will sleep 1000 ms!");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("I will try retrieve the client again!");
                    }
                    System.out.println("client:"+socketChannel+" connected!");
        
                    // read the message from client
                    int read = socketChannel.read(byteBuffer);
                    byteBuffer.flip();
                    String cliMsg = new String(byteBuffer.array(),0,read,"UTF-8");
                    System.out.println("get the client message:"+cliMsg);
        
                    // business logic
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
        
                    // response message
                    String response = "Hello,"+cliMsg;
                    byteBuffer.clear();
                    byteBuffer.put(response.getBytes("UTF-8"));
                    byteBuffer.flip();
                    socketChannel.write(byteBuffer);
                    socketChannel.close();
                    break;
                }
                serverSocketChannel.close();
            }
        }
        

        Client:

        public class NonBlockingClient {
        
            public static void main(String[] args) throws IOException {
                SocketChannel socketChannel = SocketChannel.open();
                socketChannel.socket().connect(new InetSocketAddress("127.0.0.1",45000));
                socketChannel.configureBlocking(false);
                while (!socketChannel.finishConnect()) {
                    System.out.println("connection is not established,I will wait 10 ms!");
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("I will check the connection again!");
                }
                String msg = "夏齐";
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                byteBuffer.put(msg.getBytes("UTF-8"));
                byteBuffer.flip();
                socketChannel.write(byteBuffer);
                byteBuffer.clear();
                int read = -1;
                while ((read = socketChannel.read(byteBuffer)) <= 0) {
                    System.out.println("I am not read the server message!");
                }
                System.out.println("server msg:"+new String(byteBuffer.array(),0,read,"UTF-8"));
                socketChannel.close();
            }
        }
        

        Server with Selector:

        public class NonBlockingServerWithSelector {
        
            /**
             * the selector
             */
            private final Selector selector;
        
            /**
             * the ServerSocketChannel
             */
            private final ServerSocketChannel serverSocketChannel;
        
            /**
             * the listening port
             */
            private final int port = 45000;
        
            /**
             * the read write buffer
             */
            private final ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        
            public NonBlockingServerWithSelector() throws IOException {
                selector = Selector.open();
                serverSocketChannel = ServerSocketChannel.open();
            }
        
            /**
             * start the server
             */
            public void start() throws IOException {
                // config the serverSocketChannel to non-blocking mode
                serverSocketChannel.configureBlocking(false);
        
                // bind the serverSocketChannel id address and port
                serverSocketChannel.socket().bind(new InetSocketAddress(port));
        
                // register the channel to the selector
                serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        
                System.out.println("server start,listening "+port+" port!");
                while (true) {
                    // will blocking to wait at least one channel to ready
                    selector.select();
        
                    // retrieve all the ready interested events
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = selectionKeys.iterator();
        
                    while (iterator.hasNext()) {
                        SelectionKey selectionKey = iterator.next();
                        processSelectionKey(selectionKey);
                        iterator.remove();
                    }
                }
            }
        
            private void processSelectionKey(SelectionKey selectionKey) throws IOException {
                if (selectionKey.isValid()) {
                    // process the accept event
                    if (selectionKey.isAcceptable()) {
                        SocketChannel socketChannel = serverSocketChannel.accept();
                        System.out.println("retrieve the client connection:"+socketChannel);
                        // config the channel to non-blocking mode
                        socketChannel.configureBlocking(false);
        
                        // register the socketChannel to the selector
                        socketChannel.register(selector,SelectionKey.OP_READ);
                        return;
                    }
        
                    // process the read event
                    if (selectionKey.isReadable()) {
                        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                        if (processSocketChannel(socketChannel)) {
                            socketChannel.close();
                        }
                    }
                }
            }
        
            /**
             * process communicate with the client
             * @param socketChannel the specific socketChannel
             * @return true,if should close the socket channel,otherwise,false
             */
            private boolean processSocketChannel(SocketChannel socketChannel) throws IOException {
                // read the data into the buffer
                int read = socketChannel.read(byteBuffer);
                byteBuffer.flip();
                String cliMsg = new String(byteBuffer.array(),0,read,"UTF-8");
                System.out.println("retrieve the client message:"+cliMsg);
                byteBuffer.clear();
                // construct the response message
                String response = "Hello,"+cliMsg;
                byte[] bytes = response.getBytes("UTF-8");
                byteBuffer.put(bytes);
                byteBuffer.flip();
                int write = 0;
                while ((write = socketChannel.write(byteBuffer)) > 0) {
                }
                return true;
            }
        
            public static void main(String[] args) throws IOException {
                new NonBlockingServerWithSelector().start();
            }
        
        }
        

uct the response message
String response = “Hello,”+cliMsg;
byte[] bytes = response.getBytes(“UTF-8”);
byteBuffer.put(bytes);
byteBuffer.flip();
int write = 0;
while ((write = socketChannel.write(byteBuffer)) > 0) {
}
return true;
}

         public static void main(String[] args) throws IOException {
             new NonBlockingServerWithSelector().start();
         }
     
     }
     ```
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值