AIO 编程模型

同步和异步:
  针对IO操作,如果此操作是由java自己完成的,那么这个操作就是同步操作
  针对IO操作,如果此操作是由操作系统完成的,并在处理完成后通知我们的应用程序,所以我们的应用程序可以继续做其他事情,那么这个操作是异步
阻塞和非阻塞:
  针对某些方法,如果此方法在执行时会发生阻塞等待,那么此方法就是阻塞的
  针对某些方法,如果此方法在执行时不会发生阻塞,而是不管操作是否执行成功,都会立即返回一个状态值,那么此方法就是非阻塞的

/**
 * AIO 异步非阻塞
 * 无论BIO、AIO、NIO中,一旦建立连接了,两端都是平等的
 * @aurthor chenl on 2018/12/15
 */
public class AioServerHandler implements CompletionHandler<AsynchronousSocketChannel, AioServer> {

    /**
     * 业务处理逻辑,当请求到来后,监听成功,应该做什么事情
     * 一定要实现的逻辑:为下一次客户端请求开启监听,调用accept()
     * @param result 就是和客户端直接建立关联的通道,有通道中的相关数据。如操作系统准备好的读取数据缓存,或等待返回数据的缓存
     * @param attachment
     */
    @Override
    public void completed(AsynchronousSocketChannel result, AioServer attachment) {
        // 处理下一次客户端请求,类似递归逻辑
        attachment.getServerChannel().accept(attachment, this);
        doRead(result);
    }

    private void doRead(final AsynchronousSocketChannel channel) {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        /**
         * 异步读操作
         *  read(
         *          ByteBuffer destination, 目的地,是处理客户端传递数据的中转缓存,可不用
                    T attachment,  处理客户端传递数据的对象,通常用Buffer处理
                    CompletionHandler<Integer,? super T> handler)) 处理逻辑
         *
         */
        channel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
            /**
             * 业务逻辑,读取客户端传输数据
             * @param result
             * @param attachment 在completed方法执行时,操作系统已经将客户端请求的数据写入到Buffer缓存中了,但为复位flip(),使用前一定要复位
             */
            @Override
            public void completed(Integer result, ByteBuffer attachment) {
                System.out.println(attachment.capacity());
                // 复位
                attachment.flip();
                try {
                    System.out.println("from client : " + new String(attachment.array(), "UTF-8"));
                    doWriter(channel);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }

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

            }
        });
    }

    /**
     *  真实项目中,服务器返回的结果应该是根据客户端的请求计算得到的。
     * @param channel
     */
    private void doWriter(AsynchronousSocketChannel channel) {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        System.out.println("enter message send to client > ");
        Scanner sc = new Scanner(System.in);
        String line = sc.nextLine();
        try {
            buffer.put(line.getBytes("UTF-8"));
            // 必须复位
            buffer.flip();
            // writer()方法是异步操作,具体实现由操作系统实现。可增加get()方法,实现阻塞,等待操作系统的写操作结束
            channel.write(buffer);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 异常处理逻辑,当服务端代码出现异常的时候,应该做什么事情
     * @param exc
     * @param attachment
     */
    @Override
    public void failed(Throwable exc, AioServer attachment) {
        exc.printStackTrace();
    }
}
/**
 * AIO 异步非阻塞
 * @aurthor chenl on 2018/12/15
 */
public class AioClient {
    private AsynchronousSocketChannel channel;

    public static void main(String[] args) {
        AioClient client = new AioClient("localhost", 9999);
        try {
            System.out.println("enter message send to server > ");
            Scanner sc = new Scanner(System.in);
            String line = sc.nextLine();
            client.write(line);
            client.read();
        } finally {
            client.destory();
        }
    }

    public AioClient(String host, int port) {
        init(host, port);
    }

    private void init(String host, int port) {
        InetSocketAddress ip = new InetSocketAddress(host, port);
        try {
            // 开启客户端通道
            channel = AsynchronousSocketChannel.open();
            // 发起请求,建立连接
            channel.connect(ip);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void write(String line) {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        try {
            buffer.put(line.getBytes("UTF-8"));
            buffer.flip();
            channel.write(buffer);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    public void read() {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        // read方法是异步方法,由操作系统实现
        Future<Integer> future = channel.read(buffer);
        try {
            // get方法是阻塞方法,会等待操作系统处理结束再返回
            future.get();
            buffer.flip();
            System.out.println("from server : " + new String(buffer.array(), "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    public void destory() {
        if (channel != null) {
            try {
                channel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        channel = null;
    }
}
/**
 * AIO 异步非阻塞
 * @aurthor chenl on 2018/12/15
 */
public class AioServer {
    private static final Integer DEFAULT_PORT = 9999;
    /**
     *  线程池提高服务端效率
     */
    private ExecutorService service;
    /**
     *  服务端通道,针对服务端定义的端口号
     */
    private AsynchronousServerSocketChannel serverChannel;

    public AioServer(int port) {
        init(port);
    }

    private void init(int port) {
        System.out.println("server starting at port : " + port + "....");
        InetSocketAddress ip = new InetSocketAddress(port);
        service = new ThreadPoolExecutor(4, 4, 0, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(),
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r);
                    }
                });
        try {
            // 开启服务端通道
            serverChannel = AsynchronousServerSocketChannel.open();
            // 绑定监听端口,服务器启动成功,但未监听请求
            serverChannel.bind(ip);
            System.out.println("server started...");
            // 阻塞监听
            // accept(T attachment, CompletionHandler<AsynchronousSocketChannel,? super T> handler);
            serverChannel.accept(this, new AioServerHandler());
            TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        AioServer server = new AioServer(DEFAULT_PORT);
    }

    public ExecutorService getService() {
        return service;
    }

    public void setService(ExecutorService service) {
        this.service = service;
    }

    public AsynchronousServerSocketChannel getServerChannel() {
        return serverChannel;
    }

    public void setServerChannel(AsynchronousServerSocketChannel serverChannel) {
        this.serverChannel = serverChannel;
    }
}
  1. 创建Server端,开启Server端通道,绑定端口。
  2. accept阻塞等待客户端请求.
  3. 创建客户端,开启客户端通道,建立连接,发起请求
  4. accept监听到请求,创建Handler处理器对象,将Server自身和处理器交于accept方法执行
  5. accept执行时,创建客户端通道对象交给Handler,切换环境到Handler对象内部
  6. 在Handler内部处理时,通过Server对象调用accept()开启监听,以监听下一次请求
  7. 异步读(服务端操作系统等待客户端发送数据过来。)客户端通道缓存中的数据
  8. 客户端以write异步写来发起请求数据“你好”(客户端操作系统将请求数据写入到客户端通道,通知客户端writer()完毕)
  9. 服务端操作系统读取客户端通道中数据到缓存,并通知服务端read()完毕。
  10. 客户端以read异步读来读取响应数据(客户端操作系统等待从客户端通道中读取数据到缓存中,通知客户端端read()完毕)
  11. 服务端读取、处理请求数据,生成响应数据,以异步写(服务器操作系统将数据写入到客户端通道,并通知服务端write()完毕)入客户端通道缓存中
  12. 客户端get()阻塞等待通知,读取数据
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值