“This is the 13th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”
Summary of the Channel
A Channel is a Channel through which data can be read and written. It is like a water pipe. Network data can be read and written through a Channel. The difference between a channel and a stream is that the channel is bidirectional, the stream only moves in one direction (a stream must be an InputStream or a subclass of OutputStram), and the channel can be used for reading, writing, or reading. Because channels are full-duplex, they map the underlying operating system apis better than streams.
NIO encapsulates the cao lock on the data source through a Channel, through which we can manipulate the data source without caring about its specific unreasonable structure. The data source can be many things, such as a file or a network socket. In most applications, channels correspond one to one with file descriptors or sockets. A channel effectively transfers data between a byte buffer and an entity (usually a file or socket) on the other side of the channel.
Channel interface source code
public interface Channel extends Closeable {
/**
* Tells whether or not this channel is open.
*
* @return <tt>true</tt> if, and only if, this channel is open
*/
public boolean isOpen();
/**
* Closes this channel.
*
* <p> After a channel is closed, any further attempt to invoke I/O
* operations upon it will cause a {@link ClosedChannelException} to be
* thrown.
*
* <p> If this channel is already closed then invoking this method has no
* effect.
*
* <p> This method may be invoked at any time. If some other thread has
* already invoked it, however, then another invocation will block until
* the first invocation is complete, after which it will return without
* effect. </p>
*
* @throws IOException If an I/O error occurs
*/
public void close() throws IOException;
}
Copy the code
Unlike buffers, channel apis are primarily specified by interfaces. Different operating system channel implementations are fundamentally different, so the channel API just describes what can be done. So naturally, the channel implementation airport uses OS native code. The channel interface allows you to access the underlying I/O services in a controlled and portable manner.
A Channel is an object through which data can be read and written. To compare NIO to the original I/O, channels are streams, and all data is processed through Buffer objects. You never write bytes directly to a channel; instead, you write data to a buffer containing multiple bytes. Again, instead of reading the bytes directly from the channel, you read the data from the channel into the buffer and get the bytes from the buffer.
Java NIO channels are like streams, but different:
-
Data can be read by a channel summary or written to a channel, but reads and writes to streams are usually one-way.
-
Channels can be read and written asynchronously.
-
Data in a channel is always read to buffer first, or always needs to be written from a buffer.
As mentioned above, data is read from channel to buffer and written from buffer to channel. As shown below:
The Channel to realize
Here are the most important Channel implementations in Java NIO:
-
FileChannel
-
DatagramChannel
-
SocketChannel
-
ServerSocketChannel
(1) FileChannel reads and writes data from the file
(2) DatagramChannel can read and write network data through UDP
(3) SocketChannel can write data on the network through TCP
(4) ServerSocketChannel can listen for incoming TCP connections, just like the WBE service, and create a SocketChannel for each incoming connection.
As you can see, these channels cover UDP and TCP network IO, as well as file IO.
FileChannel introduction and examples
The FileChannel class implements the common read and write and Scatter and Gather operations, as well as many new file-specific methods. Many of these methods are familiar file operations.
methods | operation |
---|---|
int read *( *ByteBuffer dst ) | Read data from Channel to ByteBuffer |
long read *( *ByteBuffer *[] *dsts ) | “Scatter” the data in a Channel into ByteBuffer |
int write *( *ByteBuffer src ) | Writes data from ByteBuffer to a Channel |
long write *( *ByteBuffer *[] *srcs ) | “Aggregates” the data in ByteBuffer[] into a Channel |
long position (a) | Returns the file location for this channel |
FileChannel position *( *long newPosition ) | Sets the file location for this channel |
long size (a) | Returns the current size of the file for this channel |
FileChannel truncate *( *long size ) | Intercepts the file for this channel to the given size |
void force *( *boolean metaData ) | Forces all files on this channel to be updated and written to the storage device |
Here is an example of reading data into a buffer using FileChannel:
Public class FileChannelDemo {// FileChannel reads data into the buffer public static void main(String[] args) throws IOException { // Create FileChannel RandomAccessFile accessFile = new RandomAccessFile("C:\a.txt", "rw"); FileChannel fileChannel = accessFile.getChannel(); ByteBuffer = ByteBuffer. Allocate (48); while (fileChannel.read(byteBuffer) ! Println (" read: "+ byteBuffer); byteBuffer.flip(); while (byteBuffer.hasRemaining()) { System.out.println((char) byteBuffer.get()); } byteBuffer.clear(); } fileChannel.close(); System.out.println("end"); }}Copy the code
Common operations of Buffer
Writes data to a buffer
Call buffer.filp() to reverse the read/write mode
Read data from the buffer
Call buffer.clear() or buffer.compact() to clear the buffer contents
FileChannel operation and detailed solution
Open the FileChannel
Before you can use a FileChannel, you have to open it, but you can’t open a FileChannel directly, To get an instance of FileCannel, use an InputStream, OutputStream, or RandomAccessFile. Here’s a practical example of opening FileChannel with RandomAccessFile:
RandomAccessFile accessFile = new RandomAccessFile("C:\a.txt", "rw");
FileChannel fileChannel = accessFile.getChannel();
Copy the code
Reads data from a FileChannel
Call one of the Duldagon read() methods to read data from the File Channel. Such as:
ByteBuffer byteBuffer = ByteBuffer.allocate(48);
byteBuffer = accessFile.read(byteBuffer);
Copy the code
A Buffer is allocated, and the data read from the FileChannel is read into the Buffer. The filechannel.read () method is then called. This method reads data from the FileChanel into the Buffer. The int returned by the read() method indicates how many bytes were read into the Buffer. If -1 is returned, the end of the file is reached.
Write data to FileChannel
Write data to FileChannel via the filechannel.write () method, which takes buffer as an argument.
Such as:
Public class FileChannelDemo2 {// FileChannel reads data into the buffer public static void main(String[] args) throws IOException {// Create FileChannel RandomAccessFile accessFile = new RandomAccessFile("C:\a.txt", "rw"); FileChannel fileChannel = accessFile.getChannel(); String newData = "new string to write to file ..." + System.currentTimeMillis(); ByteBuffer = ByteBuffer. Allocate (1024); byteBuffer.clear(); byteBuffer.put(newData.getBytes()); byteBuffer.flip(); while (byteBuffer.hasRemaining()) { fileChannel.write(byteBuffer); } fileChannel.close(); System.out.println("end"); }}Copy the code
Note that filechannel.wrte () is called in the while loop, and since there is no guarantee that the write method will write many bytes to FileChannel at once, the write() method needs to be called repeatedly, Until there are no bytes in the Buffer that have not yet been written to the channel.
Close the FileChannel
FileChannel must be turned off when you’re done with it. Such as:
fileChannel.close();
Copy the code
Position method of FileChannel
Sometimes you may need to read/write data at a specific location on the FileChannel. You can get the current position of the FileChannel by calling the position() method. You can also set the current position of the FileChannel by calling the position(long pos) method.
Here are two examples:
long pos = channel.position();
channel.position(pos + 123);
Copy the code
If it is set after the end-of-file character and then attempts to read data from the file channel, the read method returns -1 (end-of-file identifier).
If you place the position just after the end-of-file character and then write data to the channel, the file will stretch to the current position and write data. This can result in “file voids”, gaps between data written to unreasonable files on disk.
FileChannel size method
The size method of the FileChannel instance returns the size of the file associated with the instance, as in:
long fileSize = channel.size()
Copy the code
Truncate method of FileChannel
You can intercept a file using the filechannel.truncate () method. When intercepting a file, the portion of the file after the specified length will be deleted. Such as:
channel.truncate(1024);
Copy the code
This example intercepts the first 1024 bytes of a file
FileChannel force method
The filechannel.force () method forces data from the channel that has not yet been written to disk to disk. For performance reasons, the operating system caches data in memory, so there is no guarantee that data written to a FileChannel will be written to disk immediately. To ensure this, call the force method.
The force() method takes a Boolean parameter that specifies whether file metadata (permission information, etc.) is written to disk.
FileChannel 的 transferTo 和 transferFrom
Two data transfers prior to the channel:
If either channel is a FileChannel, you can transfer data directly from one channel to the other.
(1) transferForm() method
FileChannel’s transforFrom() method transfers a data re-source channel into fileChannel. Here is an example of FileChannel doing a copy between files:
Public class FileChannelWrite {public static void main(String[] args) throws IOException {// Create a FileChannel RandomAccessFile fromFile = new RandomAccessFile("C:\a.txt", "rw"); FileChannel formChannel = fromFile.getChannel(); // Create FileChannel RandomAccessFile toFile = new RandomAccessFile("C:\c. TXT ", "rw"); FileChannel toChannel = toFile.getChannel(); long position = 0; long count = formChannel.size(); toChannel.transferFrom(formChannel, position, count); formChannel.close(); toChannel.close(); System.out.println("end"); }}Copy the code
The input argument position indicates that data is written to the target file from position, and count indicates the maximum number of bytes transferred. If the free space of the source channel is less than count bytes, the number of bytes transferred is less than the number of bytes requested. Also note that in the SocketChannel implementation. SocketChannel will only transmit the data that is ready at this point (possibly less than count bytes). So SocketChannel may not transfer all of the requested data (count bytes) into the FileChannel.
(1) transferTo() method
The transferTo() method transfers data from the FileChannel to another channel
Here is an example of the transferTo() method:
Public class FileChannelWrite2 {public static void main(String[] args) throws IOException {// Create a FileChannel RandomAccessFile fromFile = new RandomAccessFile("C:\a.txt", "rw"); FileChannel formChannel = fromFile.getChannel(); // Create FileChannel RandomAccessFile toFile = new RandomAccessFile("C:\c. TXT ", "rw"); FileChannel toChannel = toFile.getChannel(); long position = 0; long count = formChannel.size(); formChannel.transferTo(position, count, toChannel); formChannel.close(); toChannel.close(); System.out.println("end"); }}Copy the code
The Socket channel
(1) The new Socket channel class can run in non-blocking mode and is optional, enabling large programs (such as network servers and middleware components) with great scalability and flexibility. As we will see in this section, it is no longer necessary to use one thread per socket connection, and the context-switching overhead of managing a large number of threads is avoided. With the new NIO class. One or a few threads can manage hundreds or thousands of active socket connections with little or no performance penalty. All socket channel classes (DatagramChannel, SocketChannel, and ServeSocketChannel). Have inherited Java nio. Channel. Spi AbstractSelectableChannel in the package. This means that we can perform Readiness selection of socket channels using a Selector object.
(2) Note that DatagramChannel and SocketChannel implementations define read and write interfaces while ServerSocketChannel implementations do not. ServerSocketChannel listens for incoming connections and creates new SocketChannel objects; it does not transmit data itself.
(3) Before we discuss each socket channel in detail, you should also understand the relationship between Sokcet and socket channels. A channel is a way to connect to and interact with an I/O service conduit. For a particular Socket, it does not implement the Socket API protocol of the corresponding Socket channel class, and Socket channels that already exist in Java.NET can be reused by most protocol operations.
All socket channel classes (DatagramChannel, SocketChannel, ServerSocketChannel) create an equivalent socket object when instantiated. These familiar classes from Java.NET (Socket, ServerSocket, and DatagramSocket) have been updated to recognize channels. Peer sockets can be obtained from a channel using the socket() method. In addition, all three java.NET classes are available
GetChannel () method.
(4) To place a socket channel in non-blocking mode, we rely on the public superclass of all socket channel classes: SelectableChannel. Readiness Selection is a mechanism that can be used to query a channel to determine whether it is ready to perform a target operation, such as read or write. Non-blocking I/O and selectivity are closely linked, which is why the API code for managing blocking patterns is defined in the SelectableChannel super class.
Setting or resetting the blocking mode of a channel is simple by calling the configureBlocking() method, passing true to blocking mode, and flase to non-blocking mode. You can determine which mode a socket peer is currently in by calling the isBlocking() method.
AbstractSelectableChannel. In Java implementation configureBlocking (Boolean block) method is as follows:
public final SelectableChannel configureBlocking(boolean block) throws IOException { synchronized (regLock) { if (! isOpen()) throw new ClosedChannelException(); if (blocking == block) return this; if (block && haveValidKeys()) throw new IllegalBlockingModeException(); implConfigureBlocking(block); blocking = block; } return this; }Copy the code
Non-blocking sockets are generally assumed to be used by servers because they make it easier to manage many socket channels simultaneously. However, it is also beneficial to use one or more socket channels in non-blocking mode on the client side. For example, with non-blocking socket channels, GUI programs can focus on user requests and maintain sessions with one or more servers simultaneously. There are many applications where non-blocking mode is useful.
Occasionally, we need to prevent the blocking mode of socket channels from changing. There is a BlockingLock method in the API that returns an opaque object reference. The object returned is used internally when the channel implementation modifies the blocking mode. Only the thread that owns the lock on this object can change the blocking mode of the channel.
The following is the introduction of the three channels:
ServerSocketChannel
ServerSocketChannel is a channel-based socket listener. It performs the same tasks as the familiar java.net.ServerSocket, but it adds channel semantics so it can run in non-blocking mode.
Since ServerSocketChannel does not have a bind() method, it is necessary to take out the peer socket and use it to bind to a port to open a listening connection. We are simply using the ServerSocket API to set other socket options as needed.
Like java.net.ServeerSocket, ServerScocketChannel has the accept() method. Once you have created a ServerSocketChannel and bound it with a peer socket, you can then call Accept () on one of them. If you choose to call the Accept () method on ServerSocket, it behaves like any other ServerSocket: it always blocks and returns a java.net.Socket object. Returns if you choose to call the Accept () method on ServerSocketChannel
Object of type ServerSocketChannel. The returned object can run in non-blocking mode.
In other words:
The Accept () method of ServerSocketChannel returns an object of type SocketChannel
Socketchannels can run in non-blocking mode.
The accept() method of other sockets blocks the return of the Socket object.
If ServerSocketChannel is called in non-blocking mode, when no incoming connection is waiting
ServerSocketChannel. The accept () will immediately return null. It is this ability to check connections without blocking that allows scalability and reduces complexity. Selectivity is thus achieved. We can use a selector instance to register the ServerSocketChannel object for automatic notification of new connections.
public class ServerSocketChannelDemo { public static void main(String[] args) throws IOException, InterruptedException { int port = 8888; ByteBuffer buffer = ByteBuffer.wrap("hell0 world!" .getBytes(StandardCharsets.UTF_8)); ServerSocketChannel socketChannel = ServerSocketChannel.open(); socketChannel.socket().bind(new InetSocketAddress(port)); socketChannel.configureBlocking(false); while (true) { System.out.println("Waiting for connections"); SocketChannel sc = socketChannel.accept(); if (sc == null) { System.out.println("null"); TimeUnit.SECONDS.sleep(2); } else { System.out.println("Incoming conection form: " + sc.socket().getRemoteSocketAddress()); buffer.rewind(); sc.write(buffer); sc.close(); }}}}Copy the code
Results of the visit
(1) Open ServerSocketChannel
Call the serverSocketChannel.open () method to open the ServerSocketChannel
ServerSocketChannel socketChannel = ServerSocketChannel.open();
Copy the code
(2) Disable ServerSocketChannel
Call the ServerSocketChannel. Close () method to open the ServerSocketChannel
socketChannel.close()
Copy the code
(3) Listen for new connections
By calling the ServerSocketChannel. Close () method to monitor incoming connections. When the Accept () method returns, it returns a new SocketChannel containing it. Therefore, the Accept () method blocks until a new connection arrives.
Usually more than one connection is listened for. Call the Accept method in the while loop. Here’s an example:
while (true) { System.out.println("Waiting for connections"); SocketChannel sc = socketChannel.accept(); if (sc == null) { System.out.println("null"); TimeUnit.SECONDS.sleep(2); } else { System.out.println("Incoming conection form: " + sc.socket().getRemoteSocketAddress()); buffer.rewind(); sc.write(buffer); sc.close(); }}Copy the code
(4) Blocking mode
SocketChannel sc = socketchannel.accept (); This blocks the process.
(5) Non-blocking mode
ServerSocketChannel can be set to non-blocking mode. In non-blocking mode, accept() returns immediately, or null if no new connections are made. Therefore, we need to check whether the returned SocketChannel is null, for example:
SocketChannel sc = socketChannel.accept();
if (sc == null) {
System.out.println("null");
TimeUnit.SECONDS.sleep(2);
} else {
System.out.println("Incoming conection form: " +
sc.socket().getRemoteSocketAddress());
buffer.rewind();
sc.write(buffer);
sc.close();
}
Copy the code
SocketChannel
Introduce a SocketChannel
In JAVA NIO, a SocketChannel is a channel that connects to a TCP network socket
A selectable channel for stream-oriented connection sockets
SocketChannel is an optional channel for connecting to sockets.
- SocketChannel is used to connect to Socket sockets
- SocketChannel is used to process network I/O channels
- Socketchannels are transmitted over TCP connections
- Socketchannels implement alternative channels that can be multiplexed
SokectChannel characteristics
(1) A SocketChannel cannot be created for an existing socket
(2) The open interface provided in SocketChannel creates a Channel that does not enjoy network cascading and needs to use the Conect interface to connect to the specified address
(3) When an I/O operation is performed on an unconnected SocketChannel, NotYesConnectedException is thrown
(4) SocketChannel supports two I/O modes: blocking and non-blocking
(5) SocketChannel supports asynchronous shutdown. If read blocks on one thread of a SocketChannel, another thread calls shutdownInput on that SocketChannel. The thread that blocks will return -1, indicating that there is no data; If a SocketChannel write block on a thread, another thread calls to the SocketChannel shutdownwrite, write blocked thread will throw AsynchronousCloseException.
(6) SocketChannel supports setting parameters:
SO_SNDBUF Size of the socket send buffer
SO_RCVBUF Socket accepts buffer size
SO_KEEPALIVE Keepalive connection
O_REUSEADDR Specifies the address to be multiplexed
SO_LINGER has delayed Channel closure during data transfer (useful only in non-blocking mode)
TCP_NODELAY Disables the Nagle algorithm
Use a SocketChannel
(1) Create SokcetChannel
Methods a
Socketchannel SocketChannel = socketchannel. open(new InetSocketAddress("www.baidu.com", 80));Copy the code
Way 2
SocketChannel socketChannel1 = SocketChannel.open();
socketChannel1.connect(new InetSocketAddress("www.baidu.com", 80));
Copy the code
Using either the open API with arguments or the no-fail OPEN API creates a SocketChannel object without actually making a TCP connection
(2) Link verification
// test whether SocketChannel isOpen socketchannel.isopen (); / / test whether a SocketChannel has been link SocketChannel. IsConnected (); Are / / test SocketChannel link state SocketChannel. IsConnectionPending (); / / check whether ongoing socket connection SocketChannel has already completed link SocketChannel. FinishConnect ();Copy the code
(3) Read/write mode
As mentioned earlier, SocketChannels support both blocking and non-blocking modes
socketChannel.configureBlocking(false);
Copy the code
Set the read/write mode of SocketChannel. False indicates non-blocking and true indicates blocking.
(4) Reading and writing
SocketChannel socketChannel0 = SocketChannel.open(
new InetSocketAddress("www.baidu.com", 80));
ByteBuffer byteBuffer = ByteBuffer.allocate(16);
socketChannel0.read(byteBuffer);
socketChannel0.close();
System.out.println("read over");
Copy the code
This is a blocking read. When it reaches read, the thread blocks and the console cannot print “read over”.
SocketChannel socketChannel10 = SocketChannel.open(
new InetSocketAddress("www.baidu.com", 80));
socketChannel10.configureBlocking(false)
ByteBuffer byteBuffer1 = ByteBuffer.allocate(16);
socketChannel10.read(byteBuffer1);
socketChannel10.close();
System.out.println("read over");
Copy the code
This is a non-blocking read and the console will print read over
Both reads and writes are buffer-oriented, the same as the FileChannel in the previous article. \
(5) Set and obtain parameters
socketChannel5.setOption(StandardSocketOptions.SO_KEEPALIVE, Boolean.TRUE)
.setOption(StandardSocketOptions.TCP_NODELAY, Boolean.TRUE);
Copy the code
The setOption method allows you to set the parameters of the socket
socketChannel5.getOption(StandardSocketOptions.SO_KEEPALIVE);
socketChannel5.getOption(StandardSocketOptions.SO_RCVBUF);
Copy the code
The parameter values can be obtained through geOption if the default buffer size of 8192 bytes is accepted
SocketChannel also supports multiplexing, which is described later.
DatagramChannel
Just as SocketChannel corresponds to Socket and ServerSocketChannel corresponds to ServerSocket, each DatagramChannel object has an associated DatagramSocket object. Just as SocketChannel emulates connection-oriented streaming protocols (e.g. TCP/IP), Datagram Channel emulates packet-oriented connectionless protocols (e.g. UDP/IP). A DatagramChannel is connectionless; each Datagram is a self-contained entity with its own destination address and data payload independent of other datagrams. Unlike socket for phase flow, DatagramChannel objects can also accept packets from any address. Each incoming data contains information about where it came from (the source address).
Open the DatagramChannel
DatagramChannel server = DatagramChannel.open();
server.socket().bind(new InetSocketAddress(25000));
Copy the code
This example is to open port 25000 to accept UDP packets.
Receive data
Receive () receives UDP packets
ByteBuffer receiveBuffer = ByteBuffer.allocate(64);
receiveBuffer.clear();
SocketAddress receiveAddr = server.receive(receiveBuffer);
Copy the code
SocketAddress Can obtain information such as the IP address and port number of packets that are sent. You can view the information using toString in the following format:
/ 127.0.0.1:57126
To send data
Send () is used to send UDP packets
DatagramChannel server1 = DatagramChannel.open(); ByteBuffer sendBuffer = ByteBuffer.wrap("client hello!" .getBytes()); Server1. Send (sendBuffer, new InetSocketAddress (25000) "127.0.0.1,");Copy the code
The connection
UDP does not exist in the full sense of connection, where the connection is to receive and send packets to a specific address with read and write.
Client. The connect (new InetSocketAddress (25000) "127.0.0.1,"); int readSize = client.read(sendBuffer); server.write(sendBuffer);Copy the code
Read () and write() can only be used after they connect freely. NotYetConnectedException must not be thrown. When receiving with read(), if no package is received, PortNnreachableException is thrown.
DatagramChannel instance
Examples of client sending and server receiving:
Public class DatagramChannelClient {public static void main(String[] args) throws IOException, InterruptedException { DatagramChannel sendChannel = DatagramChannel.open(); InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 25000); While (true) {ByteBuffer = bytebuffer.wrap (" Send DataGram test data ".getBytes(standardCharsets.utf_8)); sendChannel.send(buffer, socketAddress); System.out.println("send success!" ); TimeUnit.SECONDS.sleep(2); Public class DatagramChannelServer {public static void main(String[] args) throws IOException { DatagramChannel server = DatagramChannel.open(); server.socket().bind(new InetSocketAddress(25000)); ByteBuffer receiveBuffer = ByteBuffer.allocate(1024); while (true) { receiveBuffer.clear(); SocketAddress receiveAddress = server.receive(receiveBuffer); receiveBuffer.flip(); System.out.println(receiveAddress.toString()); System.out.println(StandardCharsets.UTF_8.decode(receiveBuffer)); }}}Copy the code
Server side print:
\
Client printing:
Connection test code
public class DatagramChannelClient2 { public static void main(String[] args) throws IOException, InterruptedException { DatagramChannel channel = DatagramChannel.open(); InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 25000); channel.bind(socketAddress); channel.connect(socketAddress); ByteBuffer = bytebuffer.wrap (" Send DataGram test data ".getBytes(standardCharsets.utf_8)); channel.write(buffer); System.out.println("write success!" ); // buffer ByteBuffer readBuffer = ByteBuffer.allocate(1024); while (true) { readBuffer.clear(); channel.read(readBuffer); readBuffer.flip(); System.out.println(StandardCharsets.UTF_8.decode(readBuffer)); TimeUnit.SECONDS.sleep(2); }}}Copy the code
The data to print
Scatter/Gather
Java NIO is starting to support Scatter/Gather, which describes reading and writing from a channel.
Scatter reading from channel means that the read data is written to multiple buffers during the read operation. Therefore, Channel “scatter” the read data from Channel Z into multiple Buffers
To gather data into a channel means to write data from multiple buffers to the same channel during write operations. Therefore, a channel “gathers” data from multiple buffers and sends it to a channel
Scatter/Gather is often used when you need to separate data. For example, when you transmit a message consisting of a header and a body, you might split the body and the header into different buffers so that you can easily process the body and the header.
Scattering Reads
Scattering is reading into multiple buffers from a channel. The following picture describes:
ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = [heander, body];
channel.read(bufferArray);
Copy the code
Note that buffer is first inserted into an array, which is then used as an input parameter to channel.read().
The read() method writes data from a channel to a buffer in the order that buffers are in the array. When one buffer is full, the channel immediately writes to the other buffer.
Scattering Reads must fill the current buffer before moving the next buffer, which means it doesn’t apply to dynamic messages. In other words, if the same message and the body are present, the header must be filled (128 bytes, for example) for the Scattering to work.
Gathing Writes
Gathering Writes are written from multiple buffers to the same channel. The following picture describes:
ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = [heander, body];
channel.write(bufferArray);
Copy the code
The buffers array is an input to the write method, which writes data to channel in the order in the buffer array. Note that only data between position and limit will be written. Therefore, if a buffer contains 128 bytes of data, but only 58 bytes of data will be written to the channel. Scattering, on the other hand, is better at handling dynamic messages such as Gathering Writes.