Java NIO series of articles

  1. The underlying principles of high concurrency IO and four main IO models
  2. Four attributes and important methods of Buffer
  3. The Channel tunnel class
  4. The Selector Selector

As you know, at a broad level, a channel can represent an underlying file descriptor, such as a hardware device, a file, a network connection, etc. However, there is more to Java NIO than that. In addition to mapping to the underlying file descriptor, Java NIO channels can be much more detailed. For example, there are different implementations of NIO Channels in Java for different network transport protocol types (TCP&UDP).

The main types of channels

  • FileChannelFile channel, used for reading and writing files
  • SocketChannelSocket channel, used to read and write data over Socket TCP connections
  • ServerSocketChannelThe server socket channel (or server listening channel), which allows us to listen for TCP connection requests, creates one for each listened requestSocketChannelSocket channel.
  • DatagramChannelA datagram channel for reading and writing data over UDP.

The four channels cover file IO, TCP NETWORK IO, and UDP network IO. The following is a brief introduction to the four channels from the four important operations: get, read, write and close Channel.

FileChannel FileChannel

A FileChannel is a channel dedicated to manipulating files. FileChannel allows you to either read data from a file or write data to a file. Note that FileChannel is blocking mode and cannot be set to non-blocking mode.

Get, read, write, and close a FileChannel

Through a file copy (A.txt -> b.txt) example to introduceFileChannelGet, read, write, close

public static void copyFile(a) throws IOException {
    String srcPath = ClassLoader.getSystemResource("").getPath() + "a.txt";
    String destPath = ClassLoader.getSystemResource("").getPath() + "b.txt";

    FileInputStream fis = new FileInputStream(srcPath);
    FileOutputStream fos = new FileOutputStream(destPath);

    // 1 Obtain the FileChannel channel
    FileChannel inChannel = fis.getChannel();
    FileChannel outChannel = fos.getChannel();

    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

    // 2 Reads data from the channel into the byteBuffer buffer
    while(inChannel.read(byteBuffer) ! = -1) {
        // Switch to read mode
        byteBuffer.flip();

        // 3 Reads data from byteBuffer and writes it to FileChannel
        while(outChannel.write(byteBuffer) ! =0) {}// Clear the buffer and switch to write mode
        byteBuffer.clear();
    }

    // 4 Forcibly flushes data to hard disks
    outChannel.force(true);

    // 5 Close the channel
    inChannel.close();
    outChannel.close();
}
Copy the code

SocketChannel SocketChannel

In NIO, there are two channels that involve network connectivity

  • SocketChannelResponsible for connection transmission
  • ServerSocketChannelResponsible for connection monitoring

Both ServerSocketChannel and SocketChannel support blocking and non-blocking modes. How do you set the mode? Call the configureBlocking method as follows:

  • SocketChannel. ConfigureBlocking (false)Set to non-blocking mode.
  • SocketChannel. ConfigureBlocking (true)Set to blocking mode.

In blocking mode, SocketChannel’s connect, read, and write operations are synchronous and blocking, as efficient as the flow-oriented blocking read and write operations of Java’s older IO.

The following describes how to get, read, write, and close a SocketChannel by sending a message from a client to a server

The client

public class SocketChannelClient {
    private static final String HOSTNAME = "127.0.0.1";
    private static final int PORT = 8890;

    private static final SocketAddress socketAddress = new InetSocketAddress(HOSTNAME, PORT);
    
    public static void main(String[] args) throws IOException {
        client();
    }

    private static void client(a) throws IOException {
        // Get the socket transport channel
        SocketChannel socketChannel = SocketChannel.open(socketAddress);
        // Set it to non-blocking
        socketChannel.configureBlocking(false);
        
        while(! socketChannel.finishConnect()) {// If the connection is not blocked, connect will immediately return the result of the client connecting to the server
            // So you need to constantly spin to check if you are currently connected to the server
        }

        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        byteBuffer.put("hello world".getBytes());
        
        // ByteBuffer is read before writing
        byteBuffer.flip();
        socketChannel.write(byteBuffer);

        // Terminates the output method by sending an end flag to the other end of the output
        socketChannel.shutdownOutput();

        // Close the socket connectionsocketChannel.close(); }}Copy the code

The service side

public class SocketChannelServer {
    private static final String HOSTNAME = "127.0.0.1";
    private static final int PORT = 8890;

    private static final SocketAddress socketAddress = new InetSocketAddress(HOSTNAME, PORT);

    public static void main(String[] args) throws IOException {
       server();
    }

    private static void server(a) throws IOException {
        // Get the server socket
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // Change to non-blocking mode
        serverSocketChannel.configureBlocking(false);
        / / binding IP + port
        serverSocketChannel.bind(socketAddress);

        // Spin to wait for client connection
        SocketChannel socketChannel = null;
        while ((socketChannel = serverSocketChannel.accept()) == null) {
        }

        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        
        // Read data from socketChannel and write to byteBuffer
        while(socketChannel.read(byteBuffer) ! = -1) {
            // Switch to read mode
            byteBuffer.flip();
            System.out.println(new String(byteBuffer.array()));
            // The situation buffer is switched to write mode
            byteBuffer.clear();
        }
        
        // Close the socketsocketChannel.close(); serverSocketChannel.close(); }}Copy the code