zoukankan      html  css  js  c++  java
  • BIO与NIO

    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();
        		}
        		
        	}
        		
        
        
        }
        
        
  • 相关阅读:
    Entity Framework Core 2.0 新特性
    asp.net core部署时自定义监听端口,提高部署的灵活性
    asp.net core使用jexus部署在linux无法正确 获取远程ip的解决办法
    使用xshell连接服务器,数字键盘无法使用解决办法
    使用Jexus 5.8.2在Centos下部署运行Asp.net core
    【DevOps】DevOps成功的八大炫酷工具
    【Network】Calico, Flannel, Weave and Docker Overlay Network 各种网络模型之间的区别
    【Network】UDP 大包怎么发? MTU怎么设置?
    【Network】高性能 UDP 应该怎么做?
    【Network】golang 容器项目 flannel/UDP相关资料
  • 原文地址:https://www.cnblogs.com/TimerHotel/p/java_nio.html
Copyright © 2011-2022 走看看