BIO与NIO

作者: 零度微笑_019c | 来源:发表于2018-10-10 18:33 被阅读0次

    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

        本文链接:https://www.haomeiwen.com/subject/rodmaftx.html