I/O 模型1Linux I/O模型与Java NIO刨根问底探索分析ContentsI/O 模型 ................................................................................................ 1五种模型同步于异步、阻塞与非阻塞Java中的I/O .......................................................................................... 3即与,包含了文件的读写或者是网络的。在中有五种模型:从开始引入,在推出了。那么,不同的模型之间具体有什么差异,又该如何使用呢?I/O 模型在操作中,通常是分为两个阶段的:首先是等待数据就绪。然后将数据从复制到例如在中,第一个阶段就是等待从网络发送数据过来,然后存入内核的缓冲区。然后第二个阶段,将接收到的数据从内核缓冲区拷贝到用户程序中。五种I/O模型Blocking I/O即阻塞式,在中默认所有的都是的。在这种模式下,两个阶段都是阻塞的。这个过程类似这样:data = recvfrom(socket)Non-blocking I/O将设置为之后,如果数据没有就绪的时候不会阻塞住请求进程而是立即返回一个错误EWOULDBLOCK,这样请求进程可以不断尝试去获取是否有数据就绪(这个过程称之为polling。然而,在数据的拷贝阶段,这个过程还是的。 I/O 模型2do { data = recvfrom(socket)} while(data == EWOULDBLOCK)I/O multiplexing多路复用是通过单个进程管理多个网络连接的一种方式,通常有select,pool和epoll等几种方式。在这种模式下,会被设置为,通过不断轮询所有的,直到某个有数据则返回。while(true) { socket = select(sockets) // 这里如果没有一个socket是就绪的就会一直阻塞 data = recvfrom(socket) // 同样从内核拷贝数据到process的时候也是block的}一个更具体的例子:while(1){ FD_ZERO(&rset); for (i = 0; i< 5; i++ ) { FD_SET(fds[i],&rset); } puts("round again"); select(max+1, &rset, NULL, NULL, NULL); for(i=0;i<5;i++) { if (FD_ISSET(fds[i], &rset)){ memset(buffer,0,MAXBUF); read(fds[i], buffer, MAXBUF); puts(buffer); } } }除了使用select之外,还可以使用pool和epoll,但是本质上两个阶段都会。看起来除了可以处理多个连接之外没啥好处,但是如果考虑到使用多线程的话,那么recvfrom可以在线程中处理,理论上可以提高吞吐。Signal driven I/O这种模式下首先将设置为,然后通过sigaction注册一个回调。这个过程不是的,一旦数据之后,一个SIGIO的信号会发送到中,然后拷贝数据阶段依然是的。handler = () -> { recvfrom(socket)}sigaction(socket, handler)Asynchronous I/O在模式下,两个阶段都是的,跟模式的区别在于,前者是当数据之后通知应用去读取;而是内核直接将数据拷贝到完成之后通知。 Java中的I/O3同步于异步、阻塞与非阻塞同步异步、阻塞和非阻塞比较中是这样定义的:同步是指请求的进程被阻塞一直到操作结束异步不导致请求进程阻塞根据这个定义,除了之外,其他四种都是的,因为数据复制阶段(是阻塞的。Java中的I/Oblocking I/O在中构建一个简单的服务器,为每一个连接新建一个线程处理:public class EchoServer { public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(); server.bind(new InetSocketAddress(9000)); while (true) { Socket socket = server.accept(); new Thread(clientHandler(socket)).start(); } } private static Runnable clientHandler(Socket socket) { return () -> { try { BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream())); String line = ""; while (!"/quit".equals(line)) { line = reader.readLine(); writer.write(line + "\n"); writer.flush(); } } catch (IOException ex) { ex.printStackTrace(); } }; }}non-blocking I/O中主要有以下的一些类:数据缓冲容器字符集编码和解码 Java中的I/O4可以进行操作的连接用来实现机制其中,Buffer中可以存储固定大小的容器,而其中的ByteBuffer类比较特殊:可以作为操作的目标可以分配为,会尝试进行原生的操作以提高性能可以直接文件的一部分到中MappedByteBuffer,支持一些额外的文件操作可以自定义字节序使用实现一个public class NioEchoServer { public static void main(String[] args) { try (Selector selector = Selector.open(); ServerSocketChannel serverSocket = ServerSocketChannel.open()) { serverSocket.bind(new InetSocketAddress(9999)); serverSocket.configureBlocking(false); serverSocket.register(selector, SelectionKey.OP_ACCEPT); ByteBuffer buffer = ByteBuffer.allocate(4); while (true) { selector.select(); final Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> iterator = selectedKeys.iterator(); while (iterator.hasNext()) { final SelectionKey key = iterator.next(); if (key.isAcceptable()) { accept(selector, serverSocket); } else if (key.isReadable()) { readAndAnswer(buffer, key); } else { throw new RuntimeException("Unsupported operation"); } iterator.remove(); } } } catch (IOException e) { e.printStackTrace(); } } private static void accept(final Selector selector, final ServerSocketChannel serverSocket) throws IOException { SocketChannel client = serverSocket.accept(); Java中的I/O5 client.configureBlocking(false); client.register(selector, SelectionKey.OP_READ); } private static void readAndAnswer(final ByteBuffer buffer, final SelectionKey key) throws IOException { final SocketChannel client = (SocketChannel) key.channel(); client.read(buffer); buffer.flip(); String s = StandardCharsets.UTF_8.decode(buffer).toString(); System.out.println("-> " + s); buffer.clear(); }}Asynchronous I/O支持,具体有这些类:AsynchronousFileChannel用于文件异步读写;AsynchronousSocketChannel客户端异步;AsynchronousServerSocketChannel服务器异步。但性能上可能并没有太大的提升(平台),以致于中移除了对的支持:淺談