The JVM reads the data model
Program execution efficiency is more determined by I/O efficiency
Need to wait for data transmission
It is the insufficient efficiency of JVM in I/O that leads to the reduction of program efficiency. In the operating system, large pieces of data can be read directly from the hardware, and the JVM I/O prefers small pieces of data reading, which is equivalent to the operating system treating a large truck as transporting a lot of data. The JVM I/O likes to process these data one shovel at a time.
NIO is introduced into JDK4 to meet the I/O requirements of Java programs to the greatest extent
- java.nio package, which defines various Buffer related classes
- java. nio. The Channel package contains classes related to Channel and Selector
- java.nio.charset package, class related to character set
There are three core components in NIO: channel, buffer and selector
What is NIO
The traditional IO is stream oriented. One or more of itself can be read from the stream each time. It can only be read backward and cannot move forward. NIO is buffer oriented. Reading data into a buffer can move forward / backward in the buffer, which increases the flexibility of the program.
In NIO, all data needs to be transmitted through the Channel. The Channel can directly map a piece of data to memory. The Channel is bidirectional and can not only read data. You can also save data. The program cannot directly read the Channel. The Channel only interacts with the Buffer buffer.
If the thread is blocked during IO flow, when calling read()/write() to read and write data, the thread will block until the data is read or completely written. In the process of reading and writing, the thread cannot do other tasks.
NIO is not thread blocked. When a thread reads data from a Channel, if there is no available data in the Channel, the thread is not blocked and can be used for other tasks
Buffer
buffer attribute
Buffer buffer is actually an array. It wraps the contents and information of the array into a buffer object, which provides a set of methods to access these information
Important properties of buffer:
1.capacity: refers to how many data can be stored in the Buffer. The capacity is specified when creating the Buffer buffer. It cannot be modified after creation. If the Buffer is full, it needs to be emptied before data can be written.
2.position indicates the current position, that is, the write / read position of the Buffer. Just after the Buffer object is created, position is initialized to 0. When a data is written, position moves a cell to the back, and its maximum value is capacity-1
When the Buffer is switched from write mode to read mode, the position will be reset to 0. The data will be read from the beginning of the Buffer. Every time a data is read, the position will move one unit back
2.limit upper limit: refers to the first position that cannot be read or written The cells behind the upper limit can neither read nor write. In the write mode of Buffer buffer, limit indicates how many data can be written; In read mode, limit indicates the maximum number of data that can be read.
3.mark mark: set a mark position. You can call the mark method to set the mark at the position position. When you call the reset() method, you can set the position as the position of the mark mark.
0<=mark<=position<=limit<=capacity
Buffer common API s
The key buffers in NIO include Byte Buffer, charbuffer, doublebuffer, floatbuffer, intbuffer, longbuffer and shortbuffer.
These buffers cover all the basic types that can be sent through I/O: byte, char, double, and flaot Int.long, short, etc. In fact, Byte Buffer and CharBuffer are mostly used.
- Each buffer has a static method allocate(capacity), which can create a buffer with a specified capacity;
- The put() method is used to store data into the buffer;
- The get() method can read data from the buffer;
- When there is still unread data in the Buffer, you can call the compact method to compress, copy all unread data to the starting position of the Buffer, and set the position after the last unread element Set the limit property to capacity
- The capacity() method returns the size of the buffer
- hasRemaining() determines whether there is data that can be processed after the current position, that is, whether there is data that can be processed between position and limit.
- limit() returns the position of the upper limit
- mark() sets the flag position of the buffer. This value can only be between 0 – position. Later, you can set position as the position of mark through reset()
- position() can return the current position of position
- remaining() returns the amount of data between the current position and limit
- The reset() method can set position to the mark bit
- rewind(): set position to 0 and cancel the mark flag bit
- clear() clears the buffer. It only modifies the position flag bit 0 and sets the limit to capacity. The data in the buffer still exists
- The flip() method can switch the buffer from write mode to read mode, first set the limit to position, and then set the position to 0;
Demonstration of Buffer API usage
public class BufferAPI { public static void main(String[] args) { //Use character buffer -- a Chinese character and an English character are the same character size, but the byte size is different CharBuffer charBuffer=CharBuffer.allocate(12); curPosition(charBuffer);//position=0,limit=12 //Store data in buffer charBuffer.put("large"); charBuffer.put("Suddenly"); charBuffer.put("Leisurely"); curPosition(charBuffer);//position=3,limit=12 //Call flip to switch the buffer from write mode to read mode charBuffer.flip(); curPosition(charBuffer);//position=0,limit=3 //Read data from buffer System.out.print(charBuffer.get()); System.out.print(charBuffer.get()); System.out.print(charBuffer.get()); curPosition(charBuffer);//position=3,limit=3 charBuffer.clear(); curPosition(charBuffer);//position=0,limit=12,mark=-1 //Put data into buffer charBuffer.put("Small"); charBuffer.put("Friend"); charBuffer.put("friend"); curPosition(charBuffer);//position=3,limit=12 //Switch to write mode charBuffer.flip();//position=0,limit=3,mark=-1 //set mark charBuffer.mark();//mark=0 //Read another character System.out.println(charBuffer.get()); curPosition(charBuffer);//position=1,limit=3 //Call reset() to reset position to mark position charBuffer.reset(); curPosition(charBuffer);//position=0,limit=3 //Call compact to copy the unread data to the position of 0 charBuffer.compact(); curPosition(charBuffer); //Clear is called to clear, but position=0, limit=capacity, and the data still exists charBuffer.clear(); curPosition(charBuffer); //Read data System.out.println(charBuffer); curPosition(charBuffer); //Read one by one -- print the contents between position and limit one by one while(charBuffer.hasRemaining()) { System.out.println(charBuffer.get()); } curPosition(charBuffer); } //Print specific information about the current location public static void curPosition(CharBuffer charBuffer) { System.out.println("Current buffer capacity capacity: "+charBuffer.capacity() +" Current buffer limit position: "+charBuffer.limit()+ " Current buffer position Pointer position: "+charBuffer.position()); } }
Output results:
Current buffer capacity capacity: 12 Current buffer limit position: 12 Current buffer position Pointer position: 0 Current buffer capacity capacity: 12 Current buffer limit position: 12 Current buffer position Pointer position: 3 Current buffer capacity capacity: 12 Current buffer limit position: 3 Current buffer position Pointer position: 0 Large flicker current buffer capacity capacity: 12 Current buffer limit position: 3 Current buffer position Pointer position: 3 Current buffer capacity capacity: 12 Current buffer limit position: 12 Current buffer position Pointer position: 0 Current buffer capacity capacity: 12 Current buffer limit position: 12 Current buffer position Pointer position: 3 Small Current buffer capacity capacity: 12 Current buffer limit position: 3 Current buffer position Pointer position: 1 Current buffer capacity capacity: 12 Current buffer limit position: 3 Current buffer position Pointer position: 0 Current buffer capacity capacity: 12 Current buffer limit position: 12 Current buffer position Pointer position: 3 Current buffer capacity capacity: 12 Current buffer limit position: 12 Current buffer position Pointer position: 0 children Current buffer capacity capacity: 12 Current buffer limit position: 12 Current buffer position Pointer position: 0 Small Friend friend Current buffer capacity capacity: 12 Current buffer limit position: 12 Current buffer position Pointer position: 12
Buffer batch data transfer
The use of buffer is to improve the data transmission efficiency. The efficiency of reading and writing one character or one byte at a time is not high. Batch operations can be carried out. With the help of array, a piece of data in the buffer can be read into the array, and some contents of the array can also be saved into the buffer
public class BufferAPI { public static void main(String[] args) { //Use character buffer -- a Chinese character and an English character are the same character size, but the byte size is different CharBuffer charBuffer=CharBuffer.allocate(12); //Save string to buffer buffer charBuffer.put("123456654321"); //Reverse read / write mode charBuffer.flip();//position=0,limit=12 System.out.println(charBuffer);//Only the content from position to limit will be output //Receive the data in the buffer through the character array char[] dst=new char[8]; //Call the get() method to read the data in the buffer into the character array //Note that the size is always fixed during batch transmission. If the transmission size is not specified, it means that the array is filled CharBuffer charBuffer1 = charBuffer.get(dst); System.out.println(new String(dst)); //The buffer returned by the get method is the same as that defined at the beginning System.out.println(charBuffer); System.out.println(charBuffer1);//Data remaining in buffer //Continue reading the contents of the buf buffer into the character array //An exception is thrown when the buffer does not have enough data to fill the entire array //charBuffer.get(dst);//BufferUnderflowException //When reading buffer data in batch, remember to query the remaining amount of buffer //When filling a large array with data from a small buffer, the length of the remaining buffer should be specified //Transfer the remaining data in the buf buffer to the position starting from 0 of the dst array charBuffer.get(dst,0,charBuffer.remaining()); System.out.println(dst); //Loop reads data from buffer charBuffer.clear(); dst=new char[8]; while(charBuffer.hasRemaining()) { int min = Math.min(dst.length, charBuffer.remaining()); charBuffer.get(dst,0,min); System.out.println(dst); } curPosition(charBuffer); //When storing data into the buffer, you should pay attention to the shortage of buffer space, otherwise an exception will be thrown //Adjust the position of the position pointer charBuffer.position(10); //You can also store two characters at this time char[] test={'a','b','c','d'}; charBuffer.put(test,0,charBuffer.remaining()); charBuffer.clear(); System.out.println(charBuffer); } //Print specific information about the current location public static void curPosition(CharBuffer charBuffer) { System.out.println("capacity: "+charBuffer.capacity() +" limit: "+charBuffer.limit()+ " position: "+charBuffer.position()); } }
There are two ways to create a buffer
1. Allocate and create buffer. allocate() method allocates a private array with specified capacity to store elements
2. The wrapping operation creates a buffer, which uses the provided array as the storage space to store the data in the buffer, and no other space is allocated
public class BufferAPI { public static void main(String[] args) { //There are two ways to create a buffer //1.allocate() CharBuffer charBuffer1=CharBuffer.allocate(12); //2.wrap() CharBuffer charBuffer3=CharBuffer.wrap("Huyou "); curPosition(charBuffer3); char[] array=new char[12]; CharBuffer charBuffer2=CharBuffer.wrap(array); curPosition(charBuffer2); } //Print specific information about the current location public static void curPosition(CharBuffer charBuffer) { System.out.println("capacity: "+charBuffer.capacity() +" limit: "+charBuffer.limit()+ " position: "+charBuffer.position()); } }
Calling the put method to put data into the buffer will directly affect the array. Similarly, any modification to the array will directly affect the buffer object
char[] array=new char[12]; CharBuffer charBuffer2=CharBuffer.wrap(array); curPosition(charBuffer2); charBuffer2.put("Hey, hey, hey"); System.out.println(array); curPosition(charBuffer2); array[4]='Small'; array[5]='Friend'; array[6]='friend'; System.out.println(charBuffer2); curPosition(charBuffer2);
The hasArray() method determines whether there is an accessible backup array
If hasArray() returns true, you can return a reference to the backup array used by the buffer object through array()
char[] array=new char[12]; CharBuffer charBuffer2=CharBuffer.wrap(array); charBuffer2.put("Hey, hey, hey"); if(charBuffer2.hasArray()) { char[] array1 = charBuffer2.array(); System.out.println(array1); }
Replication and separation of buffers
Copy operation
public class BufferAPI { public static void main(String[] args) { CharBuffer charBuffer=CharBuffer.wrap("123456"); //Buffer copy CharBuffer duplicate = charBuffer.duplicate(); System.out.println(duplicate); //As can be seen below, the two buffers only use the same array, and the two buffer objects are different objects //The two buffers actually refer to the same array duplicate.position(4); curPosition(duplicate); curPosition(charBuffer); } //Print specific information about the current location public static void curPosition(CharBuffer charBuffer) { System.out.println("capacity: "+charBuffer.capacity() +" limit: "+charBuffer.limit()+ " position: "+charBuffer.position()); } }
The essence of buffer copying is that two different buffer objects share a buffer array
Separation operation
Separate the buffer, and the slice() method creates a new buffer according to the [position.limit) interval
public class BufferAPI { public static void main(String[] args) { CharBuffer charBuffer=CharBuffer.wrap("123456"); charBuffer.position(5); CharBuffer slice = charBuffer.slice(); curPosition(charBuffer); curPosition(slice); } //Print specific information about the current location public static void curPosition(CharBuffer charBuffer) { System.out.println("capacity: "+charBuffer.capacity() +" limit: "+charBuffer.limit()+ " position: "+charBuffer.position()); } }
Direct byte buffer
The data processed by the hard disk and the operating system are 01 binary. Only ByteBuffer byte buffer in the buffer is qualified to participate in I/O operations.
A Channel channel can only use ByteBuffer as its parameter.
Direct byte buffer is usually the best choice for I/O operation. If indirect byte buffer is used, it may cause performance loss. If an indirect byte buffer is passed to the channel, the channel may first create a temporary direct byte buffer and copy the contents of the indirect buffer to the temporary direct byte buffer to perform the underlying I/O operation.
Direct buffer is the best choice for I/O. the cost of creating direct buffer may be higher than that of creating indirect buffer. The memory used by direct buffer is allocated by calling the local operating system code, bypassing the JVM stack. Now the JVM may perform buffer optimization
The ByteBuffer.allocateDirect() method creates a direct byte buffer
Channel
Channel is a new I/O access method, which is used to transfer data between the byte buffer and the entity on the other side of the channel (which can be a file or a Socket).
The Channel can read and write data in both directions, and can also realize asynchronous reading and writing.
The program cannot directly access the channel. The channel can only interact with the Buffer buffer, that is, read the data in the channel into the Buffer buffer, and the program reads the data from the Buffer;
During the write operation, the program writes the data into the Buffer, and then writes the data from the Buffer into the Channel
Common channels:
- FileChannel: the channel for reading and writing files
- SocketChannel/ServerSocketChannel: read and write data in Socket
- Datagram channel: read and write network data through UDP.
be careful:
1. The channel cannot be created by the construction method
2. Channels cannot be reused. Once a channel is created, it means that a specific I/O service has established a connection. Once the channel is closed, the connection will disappear
3. The channel can be operated in the default blocking mode or set to non blocking mode
Scatter and Gather
Scatter and gather are important functions provided by channels (sometimes also called vector I/O)
Scatte,Gather means to implement a simple I/O operation in multiple buffers.
Scatter refers to reading data from the channel and writing these data to multiple Buffer buffers in order
Gather refers to writing data from multiple Buffer buffers to the same Channel during write operations
Scatter and Gather are often used in scenarios where the transmitted data needs to be processed separately
For example, Scatter reads data from one Channel and stores it in multiple buffers:
//Sample pseudo code ByteBuffer c1=ByteBuffer.allocate(3); ByteBuffer c2=ByteBuffer.allocate(3); ByteBuffer[] bufArray={buf1,buf2} Channel.read(bufArray);
The Read() method reads data from the Channel and stores it in the buffer in the order in the array.
Note that the buf1 buffer must be full before it can be written to the buf2 buffer.
The size of data processed with Scatter/Gather is fixed
It is not suitable for uncertain data size
FileChannel
FileChannel calls the getChannel() method through RandomAccessFile, FileInputStream and fileoutputstream objects.
Although FileChannel is bidirectional and can be read or written, the channel obtained from FileInputStream stream stream can only be read and cannot be written. If writing is performed, an exception will be thrown; the channel obtained from FileOutputStream stream can only be written and cannot be read; if the accessed file is read-only, it cannot be written.
FileChannel is thread safe, but not all operations are multithreaded. For example, operations that affect channel location or file size are single threaded.
1. Memory mapping file
The map() method of FileChannel can map the entire file on the disk to the virtual memory of the computer, and package this virtual memory as a MappedByteBuffer object. Note: Currently, when a file is mapped to the virtual memory, the contents of the file are usually not read from the hard disk to the memory.
Copy files through memory mapping:
public class BufferAPI { //The path of the current project private static final String project_path=System.getProperty("user.dir")+System.getProperty("file.separator"); //source file private final static File src=new File(project_path+"src.txt"); //Purpose document private final static File dst=new File(project_path+"tar.txt"); public static void main(String[] args) { //Put Src Txt reads tar.txt in a memory mapped manner txt //Use try resources try( FileChannel fin=new FileInputStream(src).getChannel(); FileChannel fout=new FileOutputStream(dst).getChannel(); ) { //Map the data in the fin channel to virtual memory //Parameter 1: mapping mode, readable or writable //Parameter 2, parameter 3: how many bytes are mapped from a certain location MappedByteBuffer mapBuffer = fin.map(FileChannel.MapMode.READ_ONLY, 0, src.length()); //Outputs the data in the buffer to the fout channel fout.write(mapBuffer); //You can also print the contents in the buffer mapBuffer.flip();//Switch to read mode //Create character set Charset charset = Charset.defaultCharset(); //Use the default character set to convert the bytes in buf into characters CharBuffer decode = charset.decode(mapBuffer); System.out.println("Decoded buffer: "+decode); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
2. Bidirectional transmission of filechannel
The channel obtained by using RandomAccessFile is bidirectional
Set tar Txt file, and then append it to the end of the file again
public class BufferAPI { //The path of the current project private static final String project_path=System.getProperty("user.dir")+System.getProperty("file.separator"); public static void main(String[] args) { //Use try resources try( RandomAccessFile dst=new RandomAccessFile(project_path+"tar.txt","rw"); FileChannel fout=dst.getChannel(); ) { //Map the data in channel to virtual memory MappedByteBuffer mappedByteBuffer = fout.map(FileChannel.MapMode.READ_ONLY, 0, dst.length()); //Set the position operation of the channel fout.position(dst.length()); //Write buffer data to channel fout.write(mappedByteBuffer); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
channel has only position, but not limit and capacity, because these two attributes are for buffers
3. When filechannel reads and writes files, the buffer is fixed in size
public class BufferAPI { //The path of the current project private static final String project_path=System.getProperty("user.dir")+System.getProperty("file.separator"); //source file private final static File src=new File(project_path+"src.txt"); //Purpose document private final static File dst=new File(project_path+"dst.txt"); public static void main(String[] args) { //Use try resources try( FileChannel fin=new FileInputStream(src).getChannel(); FileChannel fout=new FileOutputStream(dst).getChannel(); ) { //Defines a fixed size buffer ByteBuffer byteBuffer=ByteBuffer.allocate(48); //Constantly read data from the channel and put it into the buffer while(fin.read(byteBuffer)!=-1) { byteBuffer.flip();//The buffer is switched from write mode to read mode while(byteBuffer.hasRemaining()) { //Read data from the buffer and put it into the channel fout.write(byteBuffer); } } byteBuffer.clear(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
The file does not exist, it will be created
4. Transmission between channels
It is often necessary to batch transfer files from one location to another. Channel to channel transmission can be used directly without intermediate buffer to transfer data
Note that only FileChannel supports Channel - to - channel transmission
Channel to channel transmission is very fast. Some operating systems can directly transmit data without using user space.
public class BufferAPI { //The path of the current project private static final String project_path=System.getProperty("user.dir")+System.getProperty("file.separator"); public static void main(String[] args) { //Use try resources try( RandomAccessFile src= new RandomAccessFile(project_path+"src.txt", "rw"); FileChannel fin=src.getChannel(); FileChannel fout=new FileOutputStream(project_path+"dst.txt").getChannel(); ) { //transferTo -- transfers the data in the current channel to another channel //Parameter 1: from which position of the current channel is data transmitted //Parameter 2: how many bytes of data are transmitted //Parameter 3: destination channel //fin.transferTo(0,src.length(),fout); //transform //Parameter 1: source channel //Parameters 2 and 3 correspond to the above: how many bytes are transferred from a certain position of the original channel to the current channel fout.transferFrom(fin,0,src.length()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
5.Gather implementation
The attributes and contents of the file are stored in different buffers, and then written to another file
public class BufferAPI { //The path of the current project private static final String project_path=System.getProperty("user.dir")+System.getProperty("file.separator"); //Newline character private static final String line_separator=System.getProperty("line.separator"); //Of the current class java file private static final String curJavaFilePath=project_path+"src\\com\\NIO\\BufferAPI.java"; public static void main(String[] args) { File file=new File(curJavaFilePath); //Get file absolute path String absolutePath = file.getAbsolutePath(); //Time when the file was last modified long lastModified = file.lastModified(); String formatDate = formatDate(lastModified); //Store file attributes in buffer String headerText="file path: "+absolutePath+" "+line_separator +"file modified: "+formatDate+line_separator; ByteBuffer headerBuffer=ByteBuffer.wrap(headerText.getBytes()); //File content type ByteBuffer contentBuffer=ByteBuffer.allocate(1024); //Create a buffer array ByteBuffer[] gather={headerBuffer,contentBuffer,null}; String contentType="unkonwn"; Long length=-1l; //Map files to virtual memory try (FileChannel channel = new FileInputStream(file).getChannel();) { //Map files to virtual memory MappedByteBuffer fileData = channel.map(FileChannel.MapMode.READ_ONLY, 0, file.length()); //Save the contents of the file mapped to memory into the gather array gather[2]=fileData; //file length length=file.length(); //Returns the type of the current file String name = URLConnection.guessContentTypeFromName(file.getAbsolutePath()); StringBuilder stringBuilder=new StringBuilder(); String string = stringBuilder.append("file Len: " + length+line_separator) .append("contentType: " + name+line_separator).toString(); gather[1]=contentBuffer.put(string.getBytes()); //Reverse read / write mode contentBuffer.flip(); //Write the contents of the gather array to the file FileChannel fileChannel = new FileOutputStream(project_path + "dst.txt").getChannel(); //If the return value of write is 0, it means that the writing is finished. If it is not 0, there is still data to be written while(fileChannel.write(gather)>0) {} //When you're done, close the channel fileChannel.close(); } catch (FileNotFoundException e) { addErrorMessageToFile(gather,e.getMessage()); } catch (IOException e) { addErrorMessageToFile(gather,e.getMessage()); } } //If there is an exception in the file operation, save the exception to the error log public static void addErrorMessageToFile(ByteBuffer[] gather,String error) { ByteBuffer wrap = ByteBuffer.wrap(error.getBytes()); gather[2]=wrap; } //Time formatting public static String formatDate(Long epochSecond) { Date date=new Date(epochSecond); DateFormat dateFormat = new SimpleDateFormat("yyyy year MM month dd day HH:mm:ss"); String format = dateFormat.format(date); return format; } }
effect:
socketChannel and serverSocketChannel
ServerSocketChannel can listen for new TCP connection channels
SocketChannel is a channel that connects to a TCP network socket
Server side code - serverSocketChannel implementation
public class DHYServerSocketChannel { //Server side port number private static Integer Default_Port=80; public static void main(String[] args) throws IOException, InterruptedException { //Establish a channel for an unbound serverbasket server java.nio.channels.ServerSocketChannel ssc = java.nio.channels.ServerSocketChannel.open(); //ServerSocketChannel does not have a bind binding method. You need to first obtain the ServerSocket object through the socket() method, and then bind the port number ssc.socket().bind(new InetSocketAddress(Default_Port)); //Set the channel to non blocking mode. When there is no socket and no incoming connection, the accept () method returns null ssc.configureBlocking(false); while(true) { java.nio.channels.SocketChannel socketChannel = ssc.accept(); //If there is no connection, socketChannel=null if(socketChannel==null) { Thread.sleep(2000); } else { //Connection incoming //Send a greeting to the client first ByteBuffer byteBuffer=ByteBuffer.allocate(1024); byteBuffer.put("Hello, this is the server".getBytes()); byteBuffer.flip(); socketChannel.write(byteBuffer); //Then read the content sent from the client System.out.println("client["+socketChannel.socket().getRemoteSocketAddress()+"]"); byteBuffer.clear(); //Read the data sent by the client and save it in the buffer socketChannel.read(byteBuffer); byteBuffer.flip();//Switch to read mode //decode Charset charset = Charset.defaultCharset(); //A character buffer is produced after decoding CharBuffer decode = charset.decode(byteBuffer); System.out.println("Client message: "+decode); //Close the connection between the server and the client socketChannel.close(); break; } } } }
Client side code - SocketChannel implementation
public class DHYSocketChannel { //IP address of serverSocket --- that is, the IP address of the server private static String HOST_IP="localhost"; //serverSocket registered port number private static Integer HOST_PORT=80; public static void main(String[] args) throws IOException { InetSocketAddress address=new InetSocketAddress(HOST_IP, HOST_PORT); //Create an unconnected SocketChannel SocketChannel socketChannel = SocketChannel.open(); //Establish a connection to the server socketChannel.connect(address); //TCP connection takes some time, and the establishment of two connections requires packet dialogue //Call the finishConnect() method to complete the connection process. If no connection is successful, false is returned while(!socketChannel.finishConnect()) { System.out.println("Waiting for connection..."); } System.out.println("Connection succeeded"); //Send message to server ByteBuffer buffer=ByteBuffer.wrap("Hello, this is the client".getBytes()); while(buffer.hasRemaining()) { socketChannel.write(buffer); } //Get the message sent by the server to the client InputStream inputStream = socketChannel.socket().getInputStream(); ReadableByteChannel readableByteChannel = Channels.newChannel(inputStream);//The channels utility class obtains channels buffer.clear(); readableByteChannel.read(buffer); buffer.flip();//Switch read mode //decode Charset charset = Charset.defaultCharset(); CharBuffer decode = charset.decode(buffer); System.out.println(decode); } }
DatagramChannel
Datagram channel is a channel for sending and receiving UDP packets. Unlike TCP protocol, UDP sending does not connect or confirm whether data is received.
ByteBuffer receiveBuffer = ByteBuffer.allocate(64); receiveBuffer.clear(); SocketAddress receiveAddr = server.receive(receiveBuffer);
SocketAddress can obtain the ip, port and other information of the contract. Use toString to view it. The format is as follows
/127.0.0.1:57126
connect
udp does not have a real connection. The connection here is to receive and send data packets to a specific service address with read and write.
client.connect(new InetSocketAddress("127.0.0.1",10086)); int readSize= client.read(sendBuffer); server.write(sendBuffer);
Read () and write() can only be used after connect(), otherwise notyetconnected exception will be thrown. When receiving with read(), if no packet is received, a PortUnreachableException exception will be thrown.
Data receiver
public class DHYDatagramReceiver { public static void main(String[] args) throws IOException, InterruptedException { //Create an unbound channel DatagramChannel datagramChannel=DatagramChannel.open(); //Bind a port number datagramChannel.bind(new InetSocketAddress(80)); //Set to non blocking datagramChannel.configureBlocking(false); //Receive keyboard data Scanner sc=new Scanner(System.in); ByteBuffer buffer=ByteBuffer.allocate(1024); //Judge whether data is received while(true) { //Receive data first buffer.clear(); //Receive udp packets through receive() -- receive data from the channel and put it into the buffer InetSocketAddress receive = (InetSocketAddress) datagramChannel.receive(buffer); //Judge whether data is received if(receive==null) { Thread.sleep(2000); continue; } System.out.print("Data from: "+ receive); //Switch read mode buffer.flip(); String s = new String(buffer.array(), 0, buffer.limit()); System.out.println(" :"+receive.getPort()+"---->"+s); //send data String text=sc.nextLine(); //Data sent, to whom datagramChannel.send(ByteBuffer.wrap(text.getBytes()),receive); } } }
Data sender
public class DHYDatagramSender { public static void main(String[] args) throws IOException { //Create unbound channel DatagramChannel datagramChannel = DatagramChannel.open(); datagramChannel.configureBlocking(false); ByteBuffer byteBuffer = ByteBuffer.allocate(1024); Scanner scanner = new Scanner(System.in); while(scanner.hasNext()) { String nextLine = scanner.nextLine(); byteBuffer.clear(); byteBuffer.put(nextLine.getBytes()); byteBuffer.flip(); //Data sent, to whom datagramChannel.send(byteBuffer,new InetSocketAddress("localhost",80)); //receive data byteBuffer.clear(); SocketAddress receive = datagramChannel.receive(byteBuffer); while (receive==null) { receive=datagramChannel.receive(byteBuffer); } byteBuffer.flip(); System.out.println(new String(byteBuffer.array(),0,byteBuffer.limit())); } } }
Pipe
The pipe pipe is used for one - way data connection between two threads
pipe has a source channel and a sink channel
Create pipe: pipe = pipe open();
To write data to the pipeline, you first need to access the sink channel
Pipe.SinkChannel sc=pipe.sink(); sc.write(buffer);
Reading data needs to go through the source channel
Pipe.SourceChannel source=pipe.source(); source.read(buffer);
Use Demo:
public static void test() throws IOException { // 1. Obtain pipeline Pipe pipe = Pipe.open(); // 2. Write buffer data to the pipeline // 2.1 get a channel Pipe.SinkChannel sinkChannel = pipe.sink(); // 2.2 defining buffers ByteBuffer buffer = ByteBuffer.allocate(48); buffer.put("send data".getBytes()); buffer.flip(); // Switch data mode // 2.3 writing data to pipeline sinkChannel.write(buffer); // 3. Read data from pipe Pipe.SourceChannel sourceChannel = pipe.source(); buffer.flip(); int len = sourceChannel.read(buffer); System.out.println(new String(buffer.array(), 0, len)); // 4. Close the pipe sinkChannel.close(); sourceChannel.close(); }
Demonstrate the use of pipe pipes for data transfer between two threads:
PipedOutPutStream and PipedInputStream are used, which are pipe output stream and pipe input stream respectively
During pipeline communication, thread A writes data to the PipedOutPutStream, and these data will be automatically sent to the corresponding PipedInputStream
Thread B can read data from PipedInputStream
public class DHYPipe { public static void main(String[] args) throws IOException { //Create an input flow pipe PipedInputStream in=new PipedInputStream(); //Create output flow pipe PipedOutputStream out=new PipedOutputStream(); //Establish a connection between the input flow pipe and the output flow pipe in.connect(out); //perhaps //out.connect(in); //Create thread new Thread(new Sender(out)).start(); new Thread(new Receiver(in)).start(); } } //Sender class Sender implements Runnable{ PipedOutputStream out; public Sender(PipedOutputStream out) { this.out = out; } @Override public void run() { //Analog sending data try { for(int i=0;i<10;i++) { out.write(("Hello, No" + i + "A big trick\n").getBytes(StandardCharsets.UTF_8)); } } catch (IOException e) { e.printStackTrace(); }finally { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } //receiving end class Receiver implements Runnable { PipedInputStream in; public Receiver(PipedInputStream in) { this.in = in; } @Override public void run() { //receive data byte[] bytes=new byte[1024]; try { int len; while((len=in.read(bytes))!=-1) { System.out.println(new String(bytes,0,len)); } } catch (IOException e) { e.printStackTrace(); } finally { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } }
Use sinkChannel and sourceChannel to complete the demonstration
public class DHYPipe { public static void main(String[] args) throws IOException { //Get pipeline Pipe pipe=Pipe.open(); //Create thread new Thread(new Sender(pipe.sink())).start(); new Thread(new Receiver(pipe.source())).start(); } } //Sender class Sender implements Runnable{ Pipe.SinkChannel sinkChannel; public Sender(Pipe.SinkChannel sinkChannel) throws IOException { this.sinkChannel = sinkChannel; //Set to non blocking sinkChannel.configureBlocking(false); } @Override public void run() { //Analog sending data try { sinkChannel.write(ByteBuffer.wrap("I'm a big fool".getBytes())); } catch (IOException e) { e.printStackTrace(); }finally { try { sinkChannel.close(); } catch (IOException e) { e.printStackTrace(); } } } } //receiving end class Receiver implements Runnable { Pipe.SourceChannel sourceChannel; public Receiver(Pipe.SourceChannel sourceChannel) { this.sourceChannel = sourceChannel; } @Override public void run() { try { ByteBuffer byteBuffer = ByteBuffer.allocate(1024); sourceChannel.read(byteBuffer); byteBuffer.flip(); Charset charset = Charset.defaultCharset(); CharBuffer decode = charset.decode(byteBuffer); System.out.println(decode); } catch (IOException e) { e.printStackTrace(); } finally { try { sourceChannel.close(); } catch (IOException e) { e.printStackTrace(); } } } }
Arrangement of supplementary knowledge points
HTTP, status code, TCP, UDP and other network protocols
Graphic summary of HTTP, status code, TCP, UDP and other network protocols (continuously updated)