网络编程之AIO

AIO介绍

AIO是JDK1.7引入的,也称为NIO 2.0

NIO的同步非阻塞类似于轮询,让Selector去询问各个通道的状态。

而AIO则是通过Future实现真正的异步,让IO就绪时由系统来通知应用程序。

核心类:

  • AsyncServerSocketChannel
  • AsyncSocketChannel

当进行如下操作时,都是异步的操作
+ connect/accept
+ write
+ read

可以通过两种方案处理结果:
+ 通过返回的Future对象获取结果
+ 通过CompletionHandler接口实现回调

对于CompletionHandler接口,里面有completedfailed方法,分别代表成功后的回调和失败后的回调。

代码示例

实现一个客户端给服务端发送数据,服务端按原数据返回的程序。

服务端:

public class Server {
    final String LOCALHOST = "localhost";
    final int DEFAULT_PORT = 8888;
    AsynchronousServerSocketChannel serverSocketChannel;

    private void close(Closeable... closeable){
        for(Closeable c:closeable){
            try {
                c.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void start(){
        try {
            // 绑定监听端口
            serverSocketChannel = AsynchronousServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(LOCALHOST,DEFAULT_PORT));
            System.out.println("启动服务器,监听端口:"+DEFAULT_PORT);

            while (true) {
                serverSocketChannel.accept(null,new AcceptHandler());
                System.in.read();
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            close(serverSocketChannel);
        }
    }
    private class AcceptHandler implements CompletionHandler<AsynchronousSocketChannel,Object>{
        @Override
        public void completed(AsynchronousSocketChannel result, Object attachment) {
            if(serverSocketChannel.isOpen()){
                serverSocketChannel.accept(null,this);
            }

            AsynchronousSocketChannel clientChannel = result;
            if(clientChannel!=null&&clientChannel.isOpen()){
                ClientHandler handler = new ClientHandler(clientChannel);
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                Map<String,Object> info = new HashMap<>();
                info.put("type","read");
                info.put("buffer",buffer);
                clientChannel.read(buffer,info,handler);

            }
        }

        @Override
        public void failed(Throwable exc, Object attachment) {
            // 处理错误
            exc.printStackTrace();
            if(serverSocketChannel.isOpen()){
                serverSocketChannel.accept(null,this);
            }
        }
    }
    private class ClientHandler implements CompletionHandler<Integer,Object>{
        private AsynchronousSocketChannel clientChannel;
        public ClientHandler(AsynchronousSocketChannel channel){
            this.clientChannel = channel;
        }
        @Override
        public void completed(Integer result, Object attachment) {
            Map<String,Object> info = (Map<String, Object>) attachment;
            String type = (String) info.get("type");
            if(type.equals("read")){
                ByteBuffer buffer = (ByteBuffer) info.get("buffer");
                buffer.flip();
                info.put("type","write");
                clientChannel.write(buffer,info,this);
                buffer.clear();
            }else if(type.equals("write")){
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                info.put("type","read");
                info.put("buffer",buffer);
                clientChannel.read(buffer,info,this);
            }
        }

        @Override
        public void failed(Throwable exc, Object attachment) {
            //处理错误
        }
    }

    public static void main(String[] args) {
        Server server = new Server();
        server.start();
    }
}

客户端:

public class Client {
    final String LOCALHOST = "localhost";
    final int DEFAULT_PORT = 8888;
    AsynchronousSocketChannel clientSocketChannel;

    private void close(Closeable... closeable){
        for(Closeable c:closeable){
            try {
                c.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void start(){
        // 创建channel
        try {
            clientSocketChannel = AsynchronousSocketChannel.open();
            Future<Void> future = clientSocketChannel.connect(new InetSocketAddress(LOCALHOST, DEFAULT_PORT));
            future.get();
            // 等待用户的输入
            BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));
            while(true){
                String input = consoleReader.readLine();
                byte[] inputBytes = input.getBytes();
                ByteBuffer buffer = ByteBuffer.wrap(inputBytes);
                Future<Integer> writeResult = clientSocketChannel.write(buffer);
                writeResult.get();
                buffer.flip();
                Future<Integer> readResult = clientSocketChannel.read(buffer);
                readResult.get();
                String echo = new String(buffer.array());
                buffer.clear();
                System.out.println(echo);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } finally {
            close(clientSocketChannel);
        }
    }

    public static void main(String[] args) {
        Client client = new Client();
        client.start();
    }
}

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/%e7%bd%91%e7%bb%9c%e7%bc%96%e7%a8%8b%e4%b9%8baio/

(0)
彭晨涛彭晨涛管理者
上一篇 2020年2月8日 21:47
下一篇 2020年2月9日

相关推荐

  • Java基础查缺补漏01

    某些点会在不远的将来深挖。 >>是逻辑右移,>>>是算术右移 JDK6 可以使用Console.readPassword从控制台中读取密码,用户输入的过程中密码是不可见的。…

    2019年11月26日
    0590
  • Java基础查缺补漏05

    继续我的复习刷题 可以有和类名同名的函数 题目: JAVA中,下列语句哪一个正确() A. class中的constructor不可省略B. constructor必须与class…

    Java 2020年5月29日
    0140
  • Java线程池详解

    线程池就是享元模式和生产者消费者模式的应用 动手实现线程池 步骤1:自定义拒绝策略接口 @FunctionalInterface // 拒绝策略 interface RejectP…

    2020年2月3日
    0310
  • Java中的四种内部类

    我发现最近真是越来越没有东西写了。。。不可能天天学习新知识啊,最近在复习阶段了,复习的东西大多数是博客里写过的/(ㄒoㄒ)/ 复习Java基础的时候认真看了一下Java的内部类,这…

    Java 2020年5月23日
    0100
  • 线程内部的run方法可以向外抛出异常吗?

    提出问题 线程的run方法向外可以抛出异常吗,或者能被主线程捕获异常吗?比如下面这段代码: public static void main(String[] args) { try…

    Java 2020年5月20日
    06550
  • CopyOnWriteArrayList源码分析

    总结 总结放前面防止太长不看 CopyOnWriteArrayList是一个线程安全、并且在读操作时无锁的List实现。 CopyOnWriteArrayList内部通过volat…

    Java 2020年2月15日
    0200
  • Java基础查缺补漏02

    哈哈我其实没有想到这个系列真会有续集,上次写完01以后以为不会再写下去了,没想到最近牛客网刷题有些题目还是挺纠结的,这里补一补 构造器能带哪些修饰符 题目: Which of th…

    Java 2020年5月25日
    080
  • 按键排序的Map-TreeMap源码分析

    总结 总结放前面(这篇挺短的)1. TreeMap基于红黑树实现,可以对Map中的key排序2. 它的排序和定位需要依赖比较器或实现 Comparable 接口,也因此不需要key…

    Java 2020年2月16日
    0130
  • Java基础查缺补漏03(附赠哈夫曼树&哈夫曼编码)

    继续我的复习刷题 构造器显式调用父类构造方法的规则 题目: 以下程序的输出结果为 class Base{ public Base(String s){ System.out.pri…

    2020年5月27日
    0240
  • 深入理解java虚拟机第三版读书笔记01

    做笔记之前的感言 谈到《深入理解java虚拟机》,在业内可太有名了,是国内的一位大神写的一本关于java虚拟机的畅销书,基本上对java稍有深入的程序员都听说过这本书。不过遗憾的是…

    2020年1月4日
    0300

发表回复

登录后才能评论