java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java的三种IO模型详解

java的三种IO模型详解(BIO、NIO、AIO)

作者:BLUcoding

本文介绍了BIO、NIO和AIO三种不同的IO模型,分别分析了它们的工作机制、实现方式以及与BIO的对比,BIO是阻塞的,每个连接需要一个线程;NIO是同步非阻塞的,通过缓冲区和选择器实现I/O多路复用;AIO是异步的,操作系统处理IO操作,完成后通知应用程序

一、BIO 阻塞式 IO(Blocking IO)

每个客户端连接都会在一个独立的线程中处理,并且这个线程在处理 IO 操作时会阻塞,直到操作完成。

1.1、BIO 工作机制

1.2、BIO 实现单发单收

客户端:

public static void main(String[] args) {
	Socket socket = null;
	try {
		//与服务端连接
		socket = new Socket("127.0.0.1", 5000);
		//从 socket 管道中获取字节输出流
		OutputStream os = socket.getOutputStream();
		//将字节输出流包装为打印流
		PrintStream ps = new PrintStream(os);
		//发一行数据
		ps.println("Hi BIO! 与服务端通信成功");
		ps.flush();
	} catch (IOException e) {
		e.printStackTrace();
	}
}

服务端:

 public static void main(String[] args) {
 	System.out.println("===服务端启动===");
 	ServerSocket serverSocket = null;
 	try {
 		//注册端口
		serverSocket = new ServerSocket(5000);
		//监听客户端请求
		Socket socket = serverSocket.accept();
		//从 socket 管道中获取字节输入流
		InputStream is = socket.getInputStream();
		//将字节输入流包装为缓冲字符输入流
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		
		String msg;
		//读一行数据
		if ((msg = br.readLine()) != null) {
			System.out.println("服务端接收客户端信息为:" + msg);
		}
	}catch (Exception e){
		System.out.println(e.getMessage());
	}
}

1.3、BIO 实现多发多收

客户端:

public static void main(String[] args) {
    try {
        Socket socket = new Socket("localhost",9988);
        OutputStream os = socket.getOutputStream();
        PrintStream ps = new PrintStream(os);
        Scanner scanner = new Scanner(System.in);
        while (true){
            System.out.println("请输入:");
            String input = scanner.nextLine();
            ps.println(input);
            ps.flush();
        }
     } catch (IOException e) {
     	e.printStackTrace();
     }
}

服务端:

public static void main(String[] args) {
    System.out.println("===服务端启动===");
    try {
         ServerSocket ss = new ServerSocket(9988);
         Socket socket = ss.accept();
         InputStream is = socket.getInputStream();
         BufferedReader br = new BufferedReader(new InputStreamReader(is));
         String message;
         while ((message = br.readLine()) != null){
             System.out.println("服务端接收客户端信息为:" + message);
         }
     } catch (IOException e) {
		e.printStackTrace();
     }
}

1.4、BIO 实现客户端服务端多对一

服务端:

public void listen() throws IOException {
	ServerSocket serverSocket = null;
	try {
		log.info("服务启动监听");
		serverSocket = new ServerSocket(9988);
		//循环接收到客户端的连接
		while (true) {
			Socket socket = serverSocket.accept();
			//得到连接后,开启一个线程处理连接
			handleSocket(socket);
		}
	} finally {
		if(serverSocket != null){
			serverSocket.close();
		}
	}
}

private void handleSocket(Socket socket) {
	HandleSocket socketHandle = new HandleSocket(socket);
	new Thread(socketHandle).start();
}
public void run() {
	BufferedInputStream bufferedInputStream = null;
	BufferedOutputStream bufferedOutputStream  = null;
	try {
		bufferedInputStream = new BufferedInputStream(socket.getInputStream());
		byte[] bytes = new byte[1024];
		int len ;
		if ((len = bufferedInputStream.read(bytes)) > -1) {
			String result = new String(bytes,0,len);
            System.out.println("本次接收到的结果:" + result);
        }
        System.out.println("回复信息给客户端:");
        bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
        String outString = Thread.currentThread().getName() + "接收到了";
        bufferedOutputStream.write(outString.getBytes());
        bufferedOutputStream.flush();
	} catch (IOException e) {
		System.out.println("处理异常:" + e.getMessage());
	} finally {
		try {
			if (bufferedInputStream != null) {
				bufferedInputStream.close();
			}
			if (bufferedOutputStream != null) {
				bufferedOutputStream.close();
			}
		}catch (IOException e){
			System.out.println("关闭流异常:" + e.getMessage());
		}
	}
}

客户端:

public void start() throws IOException {
	Socket socket = new Socket("127.0.0.1", 8081);
	String msg = "Hi,This is the BioClient";
	BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
	byte[] bytes = msg.getBytes();
	bufferedOutputStream.write(bytes);
	bufferedOutputStream.flush();
	System.out.println("发送完毕");
	BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());
	byte[] inBytes = new byte[1024];
	int len;
	if ((len = bufferedInputStream.read(inBytes)) != -1) {
		String result = new String(inBytes, 0, len);
		System.out.println("接收到的消息="+result);
	}
	bufferedOutputStream.close();
	bufferedInputStream.close();
	socket.close();
}

1.5、BIO 模式下的端口转发思想

一个客户端的消息经由服务端发送给所有的客户端,实现群聊功能。

public class Server {

    // 定义一个静态集合
    public static List<Socket> allSocketOnLine = new ArrayList();

    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(9999);
            while (true){
                Socket socket = ss.accept();
                // 把登录的客户端socket存入到一个在线的集合中去
                allSocketOnLine.add(socket);
                // 为当前登录成功的socket分配一个独立的线程来处理
                new ServerReaderThread(socket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

public class ServerReaderThread extends Thread{

    private Socket socket;
    
    public ServerReaderThread(Socket socket){
        this.socket = socket;
    }
    
    @Override
    public void run() {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String msg;
            while ((msg = br.readLine()) != null) {
                // 发送给所有的在线socket
                sendMsgToAllClient(msg);
            }
        } catch (Exception e) {
            System.out.println("有人下线了");
            Server.allSocketOnLine.remove(socket);
        }

    }

    /**
     * 把当前客户端发来的消息发送给全部的在线socket
     * @param msg
     */
    private void sendMsgToAllClient(String msg) throws IOException {
        for (Socket sk : Server.allSocketOnLine) {
            PrintWriter pw = new PrintWriter(sk.getOutputStream());
            pw.println(msg);
            pw.flush();
        }
    }
    
}

二、NIO 同步非阻塞式 IO(Non-blocking IO)

允许线程在等待IO操作完成期间可以继续执行其他任务。

2.1、NIO 3个核心组件(缓冲区、通道、选择器)

2.2、NIO 主要特性

2.3、NIO 与 BIO 的对比

2.4、Buffer 常用子类

2.5、Buffer 重要属性

三、AIO 异步式 IO(Asynchronous IO)

异步式IO操作不会阻塞线程,而是交由操作系统处理。

完成后,操作系统会通知应用程序,或者应用程序主动查询完成状态。

使线程在等待IO完成的同时可以执行其他任务,提高了系统的并发性能。

3.1、AIO 核心组件(异步通道、完成处理器)

1.异步通道(Asynchronous Channel):AIO 中进行I/O操作的基础设施。

AIO提供了多种异步通道:

2.完成处理器(Completion Handler):用于在I/O操作完成后处理结果的回调接口。

完成处理器包含两个方法:

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文