preface:
Above, we introduced the basic API usage of FileChannel. In this article, let's take a look at the high-level API in FileChannel.
It's high-level. Really, these knowledge points make a lot of use of the advanced playing method of file transfer mapping of the operating system, which greatly improves the efficiency of our file operation. kafka and rocketMQ, which we are familiar with, also use these high-level API s to achieve such high efficiency.
We propose a requirement, which is described as follows: provide an external socket service, which is to obtain the files in the specified file directory, write them into the socket, and finally display them on the client side.
1. Traditional file network transmission process
According to this requirement, we use the following code to complete it in a conventional way:
File file = new File("D:\\test.txt"); Long size = file.length(); byte[] arr = new byte[size.intValue()]; try { // 1. Read the contents of test.txt file into arr FileInputStream fileInputStream = new FileInputStream(file); fileInputStream.read(arr); // 2. Provision of external services Socket socket = new ServerSocket(9999).accept(); // 3. Transfer to client socket.getOutputStream().write(arr); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
The above is an implementation of the simplest version.
So from the perspective of the operating system, what are the above transmission processes?
2.mmap optimization
File file = new File("D:\\test.txt"); Long size = file.length(); byte[] arr = new byte[size.intValue()]; try { // 1. Read the contents of test.txt file into arr RandomAccessFile raFile = new RandomAccessFile(file, "rwd"); FileChannel channel = raFile.getChannel(); MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, size); // 2. Provision of external services ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(9999)); serverSocketChannel.configureBlocking(false); while(true){ SocketChannel socketChannel = serverSocketChannel.accept(); if(socketChannel != null){ // 3. Transfer to client socketChannel.write(mappedByteBuffer); } } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }

3.sendFile optimization (Linux version 2.1)
File file = new File("D:\\test.txt"); Long size = file.length(); try { // 1. Read the contents of test.txt file into arr RandomAccessFile raFile = new RandomAccessFile(file, "rwd"); FileChannel channel = raFile.getChannel(); // 2. Provision of external services ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(9999)); serverSocketChannel.configureBlocking(false); while(true){ SocketChannel socketChannel = serverSocketChannel.accept(); if(socketChannel != null){ // 3. Use the transferTo method to transfer the file data to the client channel.transferTo(0, size, socketChannel); } } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }

4.sendFile optimization (Linux version 2.4)

Referring to the four operation processes in 1, there is also less user space participation, and there is no switching between user state and kernel state.
So to sum up, there are two data copies and two context switches (compared with 3, the copy from the kernel file buffer to the kernel socket buffer is reduced)
Summary:
Let's show the similarities and differences of the above four transmission modes through a chart
transmission mode | Context switching times | Number of data copies |
Traditional IO mode | 4 | 4 |
mmap mode | 4 | 3 |
sendFile(Linux2.1) | 2 | 3 |
sendFile(Linux2.4) | 2 | 2 |
First, we say zero copy from the perspective of the operating system. Because no data is duplicated between kernel buffers (only kernel buffer There's a piece of data, sendFile 2.1 The version actually has 2 copies of data, which is not zero copy). For example, in our initial example, the kernel cache and Socket The data in the buffer is duplicated. Zero copy not only brings less data replication, but also other performance advantages, such as less context switching and less CPU Cache pseudo sharing and none CPU Checksum calculation. A little more mmap and sendFile The difference.
reference resources: