Network programming AIO

Posted by Simon180 on Thu, 25 Nov 2021 21:20:41 +0100

Introduction to AIO model

AIO (Asynchronous I/O) asynchronous non blocking model supports AIO since java jdk.17. The AIO model needs the support of the operating system. The biggest feature of AIO is asynchronous capability, which works on socket and I/O.

Different from the NIO model, a read-write operation is taken as an example, just call the read and write API s directly. For read operation: when there is a stream readable, the system will spread the readable into the buffer of the read method and notify the application. Reading and writing are asynchronous, and the callback function will be actively called after completion.

In JDK 1.7, aio is also called nio.2.0. Four asynchronous channels are added under the java.nio.channels package:

  • AsynchronousSocketChannel: asynchronous operation TCP channel, mainly connected to AsynchronousServerSocketChannel, which is generally implemented on the client;
  • Asynchronous Server socketchannel: asynchronous operation of TCP channel, which mainly receives the connection of the client and is generally implemented on the server;
  • Asynchronous filechannel: operation file;
  • Asynchronous datagram Chanel: channel for asynchronous operation of UDP.

Asynchronous Server socketchannel: the socket of the network communication server in AIO

AIO implementation method, take accept method as an example.

Because the actual IO operation of asynchronous IO is entrusted to the operating system, and the application program is only responsible for notifying the operating system of IO and the interface operating system of IO completion, the asynchronous accept method call will not be blocked.

Asynchronous IO can be implemented in two ways:

1. future method

Future<AsynchronousSocketChannel> accept();

Submit an IO operation request (Accept/read/write) and return to the future to check the future. The future.get() method will block the user program until the operation is completed normally. It is relatively simple to use the future method, but the future.get() is synchronous. It is easy to enter the synchronous programming mode. This method will make the asynchronous operation of AIO a device.

2. Callback callback method

<A> void accept(A attachment, CompletionHandler<AsynchronousSocketChannel,? super A> handler)

Start receiving the connection from the client. The successful or failed connection is the response method that triggers the CompletionHandler object.

The CompletionHandler interface provides two methods:

void completed(V result, A attachment);

The method is triggered when IO is completed. The first parameter of the method represents the returned object of IO operation, and the second parameter represents the additional parameters passed in when initiating IO operation.

void failed(Throwable exc, A attachment);

This method is triggered when IO fails. The first parameter represents the exception or error caused by the failure of IO operation, and the second parameter represents the additional parameters passed in when initiating IO operation.

That is, submit an IO operation request (Accept/read/write), specify a CompletionHandler, and send a notification when the asynchronous IO operation is completed. At this time, the completed or failed methods of the CompletionHandler object will be called.

The implementation of AIO needs to fully call the operating system parameters, IO needs the support of the operating system, and concurrency also needs the support of the operating system, so the differences between different operating systems in performance will be obvious.

AIO callback programming

AIO server (Server.java):

/**
 * AIO Server code
 * @Author : quwenjing
 * @Date : 2021/11/18 19:01
 **/
public class Server {
    public static void main(String[] args) {
        try {
            //Create server channel
            AsynchronousServerSocketChannel asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open();
            //Binding port
            asynchronousServerSocketChannel.bind(new InetSocketAddress(6666));
            System.out.println("Server start");
            //Accept client connection accept
            asynchronousServerSocketChannel.accept(null,new AcceptCompletionHandler(asynchronousServerSocketChannel));
            //The BIO accept operation returns the Socket instance
            //The AIO accept operation returns AsynchronousSocketChannel
​
            //accept is an asynchronous operation, which prevents the current program from directly executing and ending
            //Method 1: while(ture) +sleep
            while (true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Callback to accept connection accept (AcceptCompletionHandler.java):

/**
 * Receive callback for connection accept
 * @Author : quwenjing
 * @Date : 2021/11/18 19:07
 **/
public class AcceptCompletionHandler implements CompletionHandler<AsynchronousSocketChannel,Object > {
//Return parameter, pass in parameter
​
    private AsynchronousServerSocketChannel channel;
    public AcceptCompletionHandler(AsynchronousServerSocketChannel channel){
        this.channel = channel;
    }
    @Override
    public void completed(AsynchronousSocketChannel result, Object attachment) {
        System.out.println("New customer connections");
        //Complete the accept connection operation
        //buffer is required for reading and writing operations
        //Create a new buffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        //Read the data of the client. The read operation is asynchronous and needs to implement the CompletionHandler object
        /*
        void read(ByteBuffer dst,A attachment,CompletionHandler<Integer,? super A> handler);
         Interpretation of asynchronous mode of read operation
         dst: Data read destination     attachment: information passed to the read callback
         CompletionHandler: When the data reading is completed, the CompletionHandler object
         */
        result.read(byteBuffer,byteBuffer,new ReadCompletionHandler(result));
​
        //Accept the connection of other clients again and call the accept method
        channel.accept(null,new AcceptCompletionHandler(channel));
    }
    @Override
    public void failed(Throwable exc, Object attachment) {
​
    }
}

Callback for read operation (ReadCompletionHandler.java):

/**
 * Callback for read operation
 * @Author : quwenjing
 * @Date : 2021/11/18 19:21
 **/
public class ReadCompletionHandler implements CompletionHandler<Integer,ByteBuffer> {
    //The result returned by the read operation is the number of reads, which should be Integer
​
    //The channel through which the user receives or sends operations
    private AsynchronousSocketChannel asynchronousSocketChannel;
    public ReadCompletionHandler(AsynchronousSocketChannel channel){
        this.asynchronousSocketChannel = channel;
    }
    @Override
    public void completed(Integer result, ByteBuffer attachment) {
        //After reading data
        //The data has been completed and written to the result variable of ByteBuffer type
        attachment.flip();
        byte[] bytes = new byte[attachment.remaining()];
        attachment.get(bytes);
        String string = null;
        try {
            string = new String(bytes,"utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        System.out.println("Data received by the server:"+string);
        attachment.clear();
​
        //Repeatedly receive the message and call the asynchronous read operation again
        this.asynchronousSocketChannel.read(attachment,attachment,new ReadCompletionHandler(this.asynchronousSocketChannel));
    }
    @Override
    public void failed(Throwable exc, ByteBuffer attachment) {
​
    }
}
​

Client (Client.java):

public class Client {
    public static void main(String[] args) {
        //Create asynchronous channel
        try {
            AsynchronousSocketChannel asynchronousSocketChannel = AsynchronousSocketChannel.open();
​
            //Connection server asynchronous mode
            asynchronousSocketChannel.connect(new InetSocketAddress("127.0.0.1",6666),asynchronousSocketChannel,new ConnectionCompletionHandler());
​
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            //Write operation
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNext()){
                String msg = scanner.nextLine();
                if (msg!=null && !"".equals(msg.trim())){
                    byteBuffer.put(msg.getBytes());
                    byteBuffer.flip();
                    asynchronousSocketChannel.write(byteBuffer);
                    byteBuffer.clear();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
​

Connection server (ConnectionCompletionHandler.java):

public class ConnectionCompletionHandler implements CompletionHandler<Void, AsynchronousSocketChannel> {
    @Override
    public void completed(Void result, AsynchronousSocketChannel attachment) {
        //Successfully connected to the server
        System.out.println("Successfully connected to the server");
    }
​
    @Override
    public void failed(Throwable exc, AsynchronousSocketChannel attachment) {
​
    }
}
​

Topics: Java IntelliJ IDEA network socket TCP/IP