Java网络通信基础系列-AIO模型

一.AIO模型

  异步非阻塞IO

  是在JDK 1.7的时候才推出的模型。

  是利用了本地操作系统的IO操作处理模式,当有IO操作产生之后,会启动有一个单独的线程,它将所有的IO操作全部交由系统完成,只需要知道返回结果即可。 主要的模式是基于操作回调的方式来完成处理的,如果以烧水为例:在烧水的过程之中你不需要去关注这个水的状态,在烧水完成后才进行通知。

 

二.实例

AIOEchoServer.java

package cn.mldn.aio.server;

import cn.mldn.info.HostInfo;

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.CountDownLatch;

class EchoHandler implements CompletionHandler<Integer,ByteBuffer> {
    private AsynchronousSocketChannel clientChannel ;
    // 是否结束交互过程,exit = true表示结束,exit = false表示继续
    private boolean exit = false ;
    public EchoHandler(AsynchronousSocketChannel clientChannel) {
        this.clientChannel = clientChannel ;
    }
    @Override
    public void completed(Integer result, ByteBuffer buffer) {
        buffer.flip() ; // 读取之前需要执行重置处理
        String readMessage = new String(buffer.array(),0,buffer.remaining()).trim() ;
        String writeMessage = "【ECHO】" + readMessage ;  // 回应的数据信息
        if ("byebye".equalsIgnoreCase(readMessage)) {
            writeMessage = "【EXIT】拜拜,下次再见!" ;
            this.exit = true ; // 结束后期的交互
        }
        this.echoWrite(writeMessage);
    }

    private void echoWrite(String content) {
        ByteBuffer buffer = ByteBuffer.allocate(100) ;
        buffer.put(content.getBytes()) ;// 向缓存中保存数据
        buffer.flip() ;
        this.clientChannel.write(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
            @Override
            public void completed(Integer result, ByteBuffer buf) {
                if (buf.hasRemaining()) {   // 缓存中是否有数据
                    EchoHandler.this.clientChannel.write(buffer,buffer,this);
                } else {
                    if(EchoHandler.this.exit == false) {    // 还没有结束
                        ByteBuffer readBuffer = ByteBuffer.allocate(100) ;
                        EchoHandler.this.clientChannel.read(readBuffer,readBuffer,new EchoHandler(EchoHandler.this.clientChannel)) ;
                    }
                }
            }

            @Override
            public void failed(Throwable exc, ByteBuffer attachment) {
                try {
                    EchoHandler.this.clientChannel.close();
                } catch (IOException e) {
                }
            }
        });
    }

    @Override
    public void failed(Throwable exc, ByteBuffer attachment) {
        try {
            this.clientChannel.close();
        } catch (IOException e) {
        }
    }
}

// 连接接收的回调处理操作
class AcceptHandler implements CompletionHandler<AsynchronousSocketChannel,AIOServerThread> {

    @Override
    public void completed(AsynchronousSocketChannel channel, AIOServerThread aioThread) {
        aioThread.getServerChannel().accept(aioThread,this) ; // 接收连接
        ByteBuffer buffer = ByteBuffer.allocate(100) ;
        channel.read(buffer,buffer,new EchoHandler(channel)) ;
    }

    @Override
    public void failed(Throwable exc, AIOServerThread aioThread) {
        System.err.println("客户端连接创建失败....");
        aioThread.getLatch().countDown();
    }
}

// 设置一个单独的服务器的处理线程
class AIOServerThread implements Runnable {
    private AsynchronousServerSocketChannel serverChannel = null; // 服务器通道
    private CountDownLatch latch = null ; // 做一个同步处理操作

    public AIOServerThread() throws Exception {
        this.latch = new CountDownLatch(1) ;// 等待线程数量为1
        this.serverChannel = AsynchronousServerSocketChannel.open(); // 打开服务器的通道
        this.serverChannel.bind(new InetSocketAddress(HostInfo.PORT)) ; // 绑定端口
        System.out.println("服务器启动成功,监听端口为:" + HostInfo.PORT);
    }

    public AsynchronousServerSocketChannel getServerChannel() {
        return serverChannel;
    }

    public CountDownLatch getLatch() {
        return latch;
    }

    @Override
    public void run() {
        this.serverChannel.accept(this,new AcceptHandler()) ;
        try {
            this.latch.await(); // 线程等待
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


public class AIOEchoServer {
    public static void main(String[] args) throws Exception {
        new Thread(new AIOServerThread()).start();
    }
}

AIOEchoClient.java

package cn.mldn.aio.client;

import cn.mldn.info.HostInfo;
import cn.mldn.util.InputUtil;

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.CountDownLatch;

class ClientReadHandler implements CompletionHandler<Integer,ByteBuffer> {
    private AsynchronousSocketChannel clientChannel ;
    private CountDownLatch latch ;
    public ClientReadHandler(AsynchronousSocketChannel clientChannel,CountDownLatch latch) {
        this.clientChannel = clientChannel ;
        this.latch = latch ;
    }
    @Override
    public void completed(Integer result, ByteBuffer buffer) {
        buffer.flip() ;
        String readMessage = new String(buffer.array(),0,buffer.remaining()) ;
        System.out.println(readMessage); // 输出读取内容
    }

    @Override
    public void failed(Throwable exc, ByteBuffer attachment) {
        try {
            this.clientChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.latch.countDown();
    }
}

class ClientWriteHandler implements CompletionHandler<Integer,ByteBuffer> {
    private AsynchronousSocketChannel clientChannel ;
    private CountDownLatch latch ;
    public ClientWriteHandler(AsynchronousSocketChannel clientChannel,CountDownLatch latch) {
        this.clientChannel = clientChannel ;
        this.latch = latch ;
    }

    @Override
    public void completed(Integer result, ByteBuffer buffer) {
        if(buffer.hasRemaining()) {
            this.clientChannel.write(buffer,buffer,this);
        } else {
            ByteBuffer readBuffer = ByteBuffer.allocate(100) ; // 读取服务端回应
            this.clientChannel.read(readBuffer,readBuffer,new ClientReadHandler(this.clientChannel,this.latch)) ;
        }
    }

    @Override
    public void failed(Throwable exc, ByteBuffer attachment) {
        try {
            this.clientChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.latch.countDown();
    }
}

class AIOClientThread implements Runnable {
    private AsynchronousSocketChannel clientChannel;
    private CountDownLatch latch;

    public AIOClientThread() {
        try {
            this.clientChannel = AsynchronousSocketChannel.open();
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.clientChannel.connect(new InetSocketAddress(HostInfo.HOST_NAME, HostInfo.PORT));
        this.latch = new CountDownLatch(1);
    }

    @Override
    public void run() {
        try {
            this.latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public boolean sendMessage(String msg) {
        ByteBuffer buffer = ByteBuffer.allocate(100) ;
        buffer.put(msg.getBytes()) ;
        buffer.flip() ;
        this.clientChannel.write(buffer,buffer,new ClientWriteHandler(this.clientChannel,this.latch));
        if("byebye".equalsIgnoreCase(msg)) {
            return false ;
        }
        return true ;
    }
}

public class AIOEchoClient {
    public static void main(String[] args) {
        AIOClientThread client = new AIOClientThread() ;
        new Thread(client).start();
        while(client.sendMessage(InputUtil.getString("请输入要发送的内容:"))) {
            ;
        }
    }
}

  先启动AIOEchoServer.java,再启动AIOEchoClient.java,运行效果如下:

posted on 2019-06-15 11:39  bijian1013  阅读(349)  评论(0)    收藏  举报

导航