“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.