Channel (1) Channel Foundation in Java NIO

Keywords: Java socket

What is Channel

It's hard to define this truth, it's a bit abstract, but we can understand it according to its purpose.

Channels are mainly used to transfer data, from one side of the buffer to the other side of the entity (such as files, sockets, etc.), and vice versa.

Channel is the conduit to access IO services, through which we can access the I/O services of the operating system with minimal overhead.

By the way, the buffer is the endpoint of sending and receiving data within the channel, as shown in the following figure.

In addition, the definition of Channel channel interface is very simple. There are only two methods to judge whether the Channel is open or closed.

public interface Channel extends Closeable {

    public boolean isOpen();

    public void close() throws IOException;

}

Create channel

Channels are mainly divided into two categories: File channel and socket channel.

The classes involved are FileChannel and three socket channel classes: Socket Channel, Server Socket Channel and Datagram Channel.

Let's look at how these channels are created.

Create FileChannel Channel Channel

FileChannel channels can only be obtained by calling getChannel() on an open Random Access File, FileInputStream, or FileOutputStream object, as follows:

        RandomAccessFile raf = new RandomAccessFile ("somefile", "r"); 
        FileChannel fc = raf.getChannel( );

Create Socket Channel Channel Channel

        SocketChannel sc = SocketChannel.open( ); 
        sc.connect (new InetSocketAddress ("somehost", someport));

Create Server Socket Channel Channel Channel

        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.socket().bind(new InetSocketAddress(somelocalport));

Creating Datagram Channel Channel Channel

        DatagramChannel dc = DatagramChannel.open( );

Use channel

When using the channel, we usually take the data from the channel and put it into the ByteBuffer object or get the data from the ByteBuffer object and put it into the channel for transmission.

In the process of using channels, we should pay attention to whether the channels are one-way or two-way channels. One-way channels can only read or write, while two-way channels are readable and writable.

If a Channel class implements the ReadableByteChannel interface, it means that it is readable and can be read by calling the read() method.

If a Channel class implements the WritableByteChannel interface, it means that it is writable and can be written by calling the write() method.

If a Channel class implements both ReadableByteChannel interface and WritableByteChannel interface, it is a two-way channel, and if only one of them is implemented, it is a one-way channel.

For example, ByteChannel is a two-way channel. In fact, the ByteChannel interface itself does not define a new API method. It is a convenient interface that aggregates inherited interfaces and renames them.

The following is an example of using channels, showing the process of copying data between two channels, with complete annotations added:

package nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;

public class Main
{

    public static void main(String[] args) throws IOException
    {
        ReadableByteChannel source = Channels.newChannel(System.in);
        WritableByteChannel dest = Channels.newChannel(System.out);
        channelCopy1(source, dest);
        // channelCopy2 (source, dest);
        source.close();
        dest.close();

    }

    private static void channelCopy1(ReadableByteChannel src, WritableByteChannel dest)
        throws IOException
    {
        ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
        while (src.read(buffer) != -1)
        {
            // Switch to Read State
            buffer.flip();
            // Not guaranteed to write all
            dest.write(buffer);
            // Release the space of read data and wait for data to be written
            buffer.compact();
        }
        // When you exit the loop, because the call is compact Method, there may be data in the buffer
        // Need to read further
        buffer.flip();
        while (buffer.hasRemaining())
        {
            dest.write(buffer);
        }
    }

    private static void channelCopy2(ReadableByteChannel src, WritableByteChannel dest)
        throws IOException
    {
        ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
        while (src.read(buffer) != -1)
        {
            // Switch to Read State
            buffer.flip();
            // Ensure that all data in the buffer is written
            while (buffer.hasRemaining())
            {
                dest.write(buffer);
            }
            // Clear Buffer
            buffer.clear();
        }
        // When you exit the loop, because the call is clear Method, there is no data in the buffer and no further processing is required.
    }

}

Close channel

We can close the channel by calling close().

An open channel represents a specific connection to a particular I/O service and encapsulates the state of the connection. When the channel closes, the connection will be lost, and then the channel will no longer connect anything.

The isOpen() method can be used to determine whether the channel is open or not. If the closed channel is read and written, it will lead to ClosedChannelException exception.

In addition, if a channel implements the InterruptibleChannel interface, the channel will be closed when the thread on the channel is interrupted, and the thread will throw ClosedByInterruptException exception.

Reference material

<Java NIO>

Posted by phrater on Mon, 08 Apr 2019 23:18:30 -0700