广西省住房和城乡建设厅网站,纯静态网站seo,太原网站建设随州,php做电商网站安全性如何java 的三种IO模型#xff08;BIO、NIO、AIO#xff09; 一、BIO 阻塞式 IO#xff08;Blocking IO#xff09;1.1、BIO 工作机制1.2、BIO 实现单发单收1.3、BIO 实现多发多收1.4、BIO 实现客户端服务端多对一1.5、BIO 模式下的端口转发思想 二、NIO 同步非阻塞式 IO#… java 的三种IO模型BIO、NIO、AIO 一、BIO 阻塞式 IOBlocking IO1.1、BIO 工作机制1.2、BIO 实现单发单收1.3、BIO 实现多发多收1.4、BIO 实现客户端服务端多对一1.5、BIO 模式下的端口转发思想 二、NIO 同步非阻塞式 IONon-blocking IO2.1、NIO 3个核心组件缓冲区、通道、选择器2.2、NIO 主要特性2.3、NIO 与 BIO 的对比2.4、Buffer 常用子类2.5、Buffer 重要属性 三、AIO 异步式 IOAsynchronous IO3.1、AIO 核心组件异步通道、完成处理器 一、BIO 阻塞式 IOBlocking IO
每个客户端连接都会在一个独立的线程中处理并且这个线程在处理 IO 操作时会阻塞直到操作完成。
每个连接都需要一个独立的线程连接数较多时会消耗大量的内存和 CPU 资源线程在处理 IO 操作时会阻塞
1.1、BIO 工作机制
客户端通过 Socket 对象与服务端建立连接从 Socket 中得到字节输入流或输出流进行数据读写。服务端通过 ServerSocket 注册端口调用 accept 方法监听客户端 Socket 请求从 Socket 中得到字节输入流或输出流进行数据读写。
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 ListSocket 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;}Overridepublic void run() {try {BufferedReader br new BufferedReader(new InputStreamReader(socket.getInputStream()));String msg;while ((msg br.readLine()) ! null) {// 发送给所有的在线socketsendMsgToAllClient(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 同步非阻塞式 IONon-blocking IO
允许线程在等待IO操作完成期间可以继续执行其他任务。
2.1、NIO 3个核心组件缓冲区、通道、选择器
缓冲区Buffer用于存储数据的对象。数据从通道读取到缓冲区或者从缓冲区写入到通道。
通道Channel既可以从通道中读取数据又可以写数据到通道
选择器Selector同时管理多个通道通过注册通道的事件如连接就绪、读就绪、写就绪使用单个线程就能处理多个通道从而管理多个网络连接提高了效率。
2.2、NIO 主要特性
非阻塞I/O允许线程在等待IO操作完成期间可以继续执行其他任务IO多路复用通过选择器NIO允许多个通道共用一个线程进行管理减少了线程的资源消耗。异步IO操作可以在通道上注册事件和回调函数实现非阻塞的IO操作内存映射文件将文件的一部分或全部直接映射到内存中这样可以像访问内存一样访问文件提高了文件处理的效率。文件锁定允许对文件的部分或全部进行锁定从而控制对文件的并发访问。
2.3、NIO 与 BIO 的对比
面向流与面向缓冲BIO 是面向流的每次从流中读一个或多个字节直至读取所有字节而 NIO 是面向缓冲区的。阻塞与非阻塞BIO 的流是阻塞的当一个线程调用 read() 或 write() 时该线程被阻塞直到有一些数据被读取或数据完全写入而 NIO 是非阻塞的一个线程从某通道发送请求读取数据它仅能得到目前可用的数据如果目前没有数据可用时就什么都不会获取。线程开销BIO 为每个客户端连接创建一个线程在大量并发连接的情况下会带来巨大的线程开销NIO 通过选择器实现 I/O多路复用在一个线程中处理多个通道减少了线程开销。
2.4、Buffer 常用子类
ByteBuffer用于存储字节数据CharBuffer用于存储字符数据ShortBuffer用于存储Short类型数据IntBuffer用于存储Int类型数据LongBuffer用于存储Long类型数据FloatBuffer用于存储Float类型数据DoubleBuffer用于存储Double类型数据
2.5、Buffer 重要属性
capacity(容量)表示 Buffer 所占的内存大小不能为负且创建后不能更改limit(限制)表示 Buffer 中可以操作数据的大小不能为负且不能大于 capacity 写模式下表示最多能往 Buffer 里写多少数据即 limit 等于 capacity 读模式下表示最多能读到多少数据即已写入的所有数据position(位置)表示下一个要读取或写入的数据的索引 缓冲区位置不能为负且不能大于其限制 初始 position 值为 0最大为 capacity – 1。当一个 byte、long 等数据写到 Buffer 后 position 会向前移动到下一个可插入数据的 Buffer 单元mark(标记)表示记录当前 position 的位置可通过 reset() 恢复到 mark 的位置 三、AIO 异步式 IOAsynchronous IO
异步式IO操作不会阻塞线程而是交由操作系统处理。完成后操作系统会通知应用程序或者应用程序主动查询完成状态。使线程在等待IO完成的同时可以执行其他任务提高了系统的并发性能。
3.1、AIO 核心组件异步通道、完成处理器 异步通道Asynchronous ChannelAIO 中进行I/O操作的基础设施。 AIO提供了多种异步通道 AsynchronousSocketChannel异步套接字通道支持面向连接的网络通信AsynchronousServerSocketChannel异步服务器套接字通道支持异步服务器端套接字通信AsynchronousFileChannel异步文件通道支持异步文件读写操作 完成处理器Completion Handler用于在I/O操作完成后处理结果的回调接口。 完成处理器包含两个方法 completed(V result, A attachment) 在I/O操作成功完成时调用 failed(Throwable exc, A attachment) 在I/O操作失败时调用。