Java NIO 2:AIO


NIO 2:AIO(异步、非阻塞)

  • AIO 是异步 IO 的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO 操作本身是同步的;
  • 但是对 AIO 来说,则更加进了一步,它不是在 IO 准备好时再通知线程,而是在 IO 操作已经完成后,再给线程发出通知。因此 AIO 是不会阻塞的,此时我们的业务逻辑将变成一个回调函数,等待 IO 操作完成后,由系统自动触发;
  • 与 NIO 不同,当进行读写操作时,只须直接调用 API 的 read 或 write 方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入 read 方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将 write 方法传递的流写入完毕时,操作系统主动通知应用程序。 即可以理解为,read/write 方法都是异步的,完成后会主动调用回调函数。 在 JDK1.7 中,这部分内容被称作 NIO.2,主要在 Java.nio.channels 包下增加了下面四个异步通道:
    • AsynchronousSocketChannel
    • AsynchronousServerSocketChannel
    • AsynchronousFileChannel
    • AsynchronousDatagramChannel
  • 在 AIO socket 编程中,服务端通道是 AsynchronousServerSocketChannel,这个类提供了一个 open() 静态工厂,一个 bind() 方法用于绑定服务端 IP 地址(还有端口号),另外还提供了 accept() 用于接收用户连接请求。在客户端使用的通道是 AsynchronousSocketChannel,这个通道处理提供 open 静态工厂方法外,还提供了 read 和 write 方法;
  • 在 AIO 编程中,发出一个事件(accept read write 等)之后要指定事件处理类(回调函数),AIO 中的事件处理类是 CompletionHandler<V,A>,这个接口定义了如下两个方法,分别在异步操作成功和失败时被回调:
    • void completed(V result, A attachment);
    • void failed(Throwable exc, A attachment);

1. 异步非阻塞连接

  • 服务器端:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;

public class Server {
    public static void main(String[] args) throws IOException {
        AsynchronousServerSocketChannel serverSocketChannel =
                AsynchronousServerSocketChannel.open()
                        .bind(new InetSocketAddress(8888));
        //异步的accept()
        serverSocketChannel.accept(null,
                new CompletionHandler<AsynchronousSocketChannel, Void>() {
                    //有客户端连接成功的回调函数
                    @Override
                    public void completed(AsynchronousSocketChannel result, Void attachment) {
                        System.out.println("服务器端接收到连接...");
                    }

                    //IO操作失败时的回调函数
                    @Override
                    public void failed(Throwable exc, Void attachment) {
                        System.out.println("IO操作失败!");
                    }
                });
        System.out.println("服务器端继续....");
        while (true) {

        }
    }
}
  • 客户端代码:
import java.net.InetSocketAddress;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;

public class Client {
    public static void main(String[] args) throws Exception {
        AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();
        //客户端异步、非阻塞connect()方法
        socketChannel.connect(new InetSocketAddress("localhost", 8888), null,
                new CompletionHandler<Void, Void>() {
                    //连接成功时的回调函数
                    @Override
                    public void completed(Void result, Void attachment) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("客户端连接成功");
                    }

                    @Override
                    public void failed(Throwable exc, Void attachment) {
                        System.out.println("客户端失败!");
                    }
                });
        System.out.println("客户端继续");
        Thread.sleep(30000);
    }
}
  • 服务器端打印:
    在这里插入图片描述
  • 客户端打印:
    在这里插入图片描述

2. 同步非阻塞读写

  • 服务器端代码:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public class Server {
    public static void main(String[] args) throws IOException {
        AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open()
                .bind(new InetSocketAddress(8888));
        //异步的accept()
        serverSocketChannel.accept(null,
                new CompletionHandler<AsynchronousSocketChannel, Void>() {
                    //有客户端连接成功的回调函数
                    @Override
                    public void completed(AsynchronousSocketChannel result, Void attachment) {
                        System.out.println("服务器端接收到连接...");
                        ByteBuffer byteBuffer = ByteBuffer.allocate(20);
                        Future<Integer> readFuture = result.read(byteBuffer);//同步读
                        try {
                            System.out.println("读取信息:" +
                                    new String(byteBuffer.array(), 0, readFuture.get()));
                            result.close();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } catch (ExecutionException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                    //IO操作失败时的回调函数
                    @Override
                    public void failed(Throwable exc, Void attachment) {
                        System.out.println("IO操作失败!");
                    }
                });
        System.out.println("服务器端继续....");
        while (true) {

        }
    }
}
  • 客户端代码:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public class Client {
    public static void main(String[] args) throws Exception {
        AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();
        socketChannel.connect(new InetSocketAddress("localhost", 8888), null,
                new CompletionHandler<Void, Void>() {
                    @Override
                    public void completed(Void result, Void attachment) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("客户端连接成功");
                        Future<Integer> writeFuture = socketChannel.write(
                                ByteBuffer.wrap("我来自客户端...".getBytes()));//同步写
                        try {
                            System.out.println("写入大小:" + writeFuture.get());
                            socketChannel.close();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } catch (ExecutionException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                    }

                    @Override
                    public void failed(Throwable exc, Void attachment) {
                        System.out.println("客户端失败!");
                    }
                });
        System.out.println("客户端继续");
        Thread.sleep(30000);
    }
}
  • 服务器端执行结果:
    在这里插入图片描述
  • 客户端执行结果:
    在这里插入图片描述

3. 异步非阻塞读写

  • 服务器端代码:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.TimeUnit;

public class Server {
    public static void main(String[] args) throws IOException {
        AsynchronousServerSocketChannel serverSocketChannel =
                AsynchronousServerSocketChannel.open().
                        bind(new InetSocketAddress(8888));
        serverSocketChannel.accept(null,
                new CompletionHandler<AsynchronousSocketChannel, Void>() {
                    @Override
                    public void completed(AsynchronousSocketChannel ch, Void attachment) {
                        serverSocketChannel.accept(null, this);
                        ByteBuffer byteBuffer = ByteBuffer.allocate(Integer.MAX_VALUE / 300);
                        System.out.println("【服务器】read开始...");
                        ch.read(byteBuffer, 10, TimeUnit.SECONDS, null,
                                new CompletionHandler<Integer, Void>() {
                                    @Override
                                    public void completed(Integer result, Void attachment) {
                                        if (result == -1) {
                                            System.out.println("客户端没有传输数据就close了...");
                                        }
                                        System.out.println("服务器读取数据:" +
                                                new String(byteBuffer.array(), 0, result));
                                        try {
                                            ch.close();
                                            System.out.println("服务器关闭!");
                                        } catch (IOException e) {
                                            e.printStackTrace();
                                        }
                                    }

                                    @Override
                                    public void failed(Throwable exc, Void attachment) {
                                        exc.printStackTrace();
                                        System.out.println(attachment);
                                        System.out.println("【服务器】异常");
                                    }
                                });
                        System.out.println("【服务器】read结束...");

                    }

                    @Override
                    public void failed(Throwable exc, Void attachment) {

                    }
                });
        System.out.println("服务器开始循环...");
        while (true) {

        }
    }
}
  • 客户端代码:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;

public class Client {
    public static void main(String[] args) throws IOException, InterruptedException {
        AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();
        socketChannel.connect(new InetSocketAddress("localhost", 8888), null, new CompletionHandler<Void, Void>() {
            @Override
            public void completed(Void result, Void attachment) {

                socketChannel.write(
                        ByteBuffer.wrap("你好服务器".getBytes()), null,
                        new CompletionHandler<Integer, Void>() {
                            @Override
                            public void completed(Integer result, Void attachment) {
                                System.out.println("输出完毕!");
                            }

                            @Override
                            public void failed(Throwable exc, Void attachment) {
                                System.out.println("输出失败!");
                            }
                        });

                try {
                    socketChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void failed(Throwable exc, Void attachment) {
                System.out.println("【客户端】异常!");
            }
        });
        Thread.sleep(1000);
    }
}
  • 服务器端输出:
    在这里插入图片描述
  • 客户端输出:
    在这里插入图片描述
发布了310 篇原创文章 · 获赞 315 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Regino/article/details/105121370