netty Learning java NIO Programming
NIO in-depth analysis
nio must read and write files through Buffer, read and write state inversion to call. flip() function, read to write, or write state to read, otherwise error will be reported.
2. Whether you read or write, you need a Buffer.
Three attribute elements in Buffer: capacity, limit, position
flip:
Capacity: It means that the number of elements (capacity) contained in Buffer can not be negative. The allocate(n) method determines the size or other methods. After allocation, capacity can not be changed again.
limit: The first element index that cannot be read or written, cannot be negative, cannot exceed its capacity
position: Index of the next element to be read or written <br>
Flp source code:
/** * Flips this buffer. The limit is set to the current position and then * the position is set to zero. If the mark is defined then it is * discarded. * <p> After a sequence of channel-read or <i>put</i> operations, invoke * this method to prepare for a sequence of channel-write or relative * <i>get</i> operations. For example: * <blockquote><pre> * buf.put(magic); // Prepend header * in.read(buf); // Read data into rest of buffer * buf.flip(); // Flip buffer * out.write(buf); // Write header + data to channel</pre></blockquote> * <p> This method is often used in conjunction with the {@link * java.nio.ByteBuffer#compact compact} method when transferring data from * one place to another. </p> * @return This buffer */ public final Buffer flip() { limit = position; position = 0; mark = -1; return this; }
The initialized state diagram is as follows, n=6
The following changes occur when four elements are read in
At this point, the flip() function is called, inverted, position returns to the first position, limit comes to the original position, the status is as follows
At this point, you can write up to four elements, and position comes to the limit:
Call flip () again, and postion returns to the first location, with limit unchanged
The clear function reinitializes the Buffer to restore the original starting state. (Data is still there, state migration, reoperation overrides the original data operation, similar to initialization)
rewind function: read again, set limit unchanged, position=0;
Thread Safety: Buffer is not safe in a multi-threaded concurrent environment. If there are multiple threads accessing the environment, synchronization is required.
Synchronized operation.
Three steps to read files through NIO:
-
Get the FileChannel object from FileInputStream.
-
Create Buffer
-
Read data from Channel to Buffer
The meaning of absolute method and relative method:
1. Relative method: limit value and position value will be considered in operation.
2. Absolute method: completely ignoring limit and position values
We can convert an ordinary Buffer to a read-only Buffer at any time, while a read-only Buffer cannot be turned back to the original standard Buffer.
NIO Out-of-heap Memory and Zero Copy
In the Buffer class, there is a long-type field called address, which marks the address of the data to be manipulated by native (operating system layer) outside the java heap and can be directly manipulated by address.
1. The method of HeapByteBuffer is to copy the data on the java heap to an extra space outside the Native heap, and then deal with the IO device. The memory is automatically maintained and recovered by the operating system.
DirectByteBuffer copies the data directly from the heap into Native's data space. No extra copy to another open space is zero copy. Memory recovery of data space is that when DirectByteBuffer is recycled, the address of this out-of-heap space can be found by address address for recovery.
Memory Mapping File
Data can be modified directly in out-of-heap memory, and the interaction between data and IO devices is automatically completed by the operating system.
public static void main(String []args)throws Exception{ RandomAccessFile randomAccessFile=new RandomAccessFile("NioTest9.txt","rw"); FileChannel fileChannel=randomAccessFile.getChannel(); //Modify data directly in memory //Get the memory mapped object through map MappedByteBuffer mappedByteBuffer=fileChannel.map(FileChannel.MapMode.READ_WRITE,0,5); //Change element 0 to a mappedByteBuffer.put(0,(byte)'a'); mappedByteBuffer.put(3,(byte)'b'); randomAccessFile.close(); }
File lock usage
public static void main(String []args)throws Exception{ RandomAccessFile randomAccessFile=new RandomAccessFile("NioText10.txt","rw"); FileChannel fileChannel=randomAccessFile.getChannel(); //Get the file lock. Lock from the third location, 6 lengths, share lock for ture, exclusive lock for false FileLock fileLock=fileChannel.lock(3,6,true); System.out.println("valid: "+fileLock.isValid()); System.out.println("lock type: "+fileLock.isShared()); //Release lock fileLock.release(); randomAccessFile.close(); }
Network communication of traditional java
It is blocked. Using multi-threaded new Thread technology can solve concurrency easily. A connection creates a new thread, but it wastes a lot of resources. The number of threads per machine has a maximum cpu. (For small-scale applications with fewer users)
NIO Non-blocking Communication
The server can process requests from multiple clients with one thread, and defines a Selector to listen for event events on multiple ports. NIO is event-triggered communication
Selector is important
Instead of introducing the source code here, check it locally.
channel source code for SelectionKey
/** * Returns the channel for which this key was created. This method will * continue to return the channel even after the key is cancelled. * * @return This key's channel */ public abstract SelectableChannel channel();
Examples of using Selector to listen on multiple clients
import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; 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.Iterator; import java.util.Set; public class NioTest12 { public static void main(String[]args) throws IOException { //Define 5 port numbers for listening int []ports=new int[5]; ports[0]=5000; ports[1]=5001; ports[2]=5002; ports[3]=5003; ports[4]=5004; Selector selector=Selector.open(); for (int i=0;i<ports.length;i++){ ServerSocketChannel serverSocketChannel=ServerSocketChannel.open(); //Configuration is blocked, false-non-blocked serverSocketChannel.configureBlocking(false); //SerrSocketChannel. socket () returns the socket associated with ServerSocketChannel ServerSocket serverSocket=serverSocketChannel.socket(); //Binding socket address InetSocketAddress address=new InetSocketAddress(ports[i]); serverSocket.bind(address); /** * Registers this channel with the given selector, returning a selection * key */ //OP_ACCEPT is interested in connection events and returns the SelectionKey object serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("Listening Port: "+ports[i]); } while (true){ //Once returned, an event exists in channel int numbers=selector.select(); System.out.println("numbers: "+numbers); //Get the corresponding event Set<SelectionKey> selectionKeys= selector.selectedKeys(); System.out.println("selectionKeys: "+selectionKeys); Iterator<SelectionKey>iter= selectionKeys.iterator(); while (iter.hasNext()){ SelectionKey selectionKey=iter.next(); if (selectionKey.isAcceptable()){ //Get ServerSocket Channel ServerSocketChannel serverSocketChannel= (ServerSocketChannel) selectionKey.channel(); SocketChannel socketChannel=serverSocketChannel.accept(); socketChannel.configureBlocking(false); //Pay attention to reading socketChannel.register(selector, SelectionKey.OP_READ); //Be sure to iter.remove(); indicates that the current event has been used up iter.remove(); System.out.println("Get the client connection:"+socketChannel); }else if (selectionKey.isReadable()){//read SocketChannel socketChannel= (SocketChannel) selectionKey.channel(); int bytesRead=0; while (true){ ByteBuffer byteBuffer=ByteBuffer.allocate(512); byteBuffer.clear(); int read=socketChannel.read(byteBuffer); if(read<=0) break; byteBuffer.flip(); socketChannel.write(byteBuffer); bytesRead+=read; } System.out.println("Read: "+bytesRead+" , From: "+socketChannel); iter.remove(); } } } } }