NIO 远程通信 demo

1、NIO 服务端

public class NIOServer extends Thread{
    //1、声明多路复用器
    private Selector selector;
    //2、定义读写缓冲区
    private ByteBuffer readBuffer = ByteBuffer.allocate(1024);
    private ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
    //3、定义构造方法初始化端口
    public NIOServer(int port){
        init(port);
    }
    //4、main方法启动线程
    public static void main(String[] args) {
        new Thread(new NIOServer(8888)).start();
    }

    private void init(int port) {
        try {
            System.out.println("服务器正在启动......");
            //1、开启多路复用器
            this.selector = Selector.open();
            //2、开启服务通道
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            //3、设置为非阻塞
            serverSocketChannel.configureBlocking(false);
            //4、绑定端口
            serverSocketChannel.bind(new InetSocketAddress(port));
            /**
             * SelectionKey.OP_ACCEPT -- 接收连接继续事件,表示服务器监听到了客户连接,服务器可以接收这个连接了
             * SelectionKey.OP_CONNECT -- 连接就绪事件,表示客户与服务器的连接建立成功
             * SelectionKey.OP_READ -- 读就绪事件,表示通道中已经有了可读的数据,可以执行操作了(通道目前有数据,可以进行读操作)
             * SelectionKey.OP_WRITE -- 写就绪事件,表示已经可以向通道写数据了(通道目前可以进行写操作)
             */
            //5、注册,标记服务连接状态为 ACCPET 状态
            serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    @Override
    public void run() {
        while (true){
            try {
                //1、当有至少一个通道被选中
                this.selector.select();
                //2、获取选中的通道编号集合
                Iterator keys = this.selector.selectedKeys().iterator();
                //3、遍历 keys
                while(keys.hasNext()){
                    SelectionKey key = keys.next();
                    //4、当前 key 需要从动刀集合中移出,如果不移出,下次循环会执行对应的逻辑,造成业务错乱
                    keys.remove();
                    //5、判断通道是否有效
                    if(key.isValid()){
                        try{
                            //6、判断是否可以连接
                            if(key.isAcceptable()){
                                accept(key);
                            }
                        }catch (CancelledKeyException e){
                            //出现异常断开连接
                            key.cancel();
                        }
                        try{
                            //7、判断是否可读
                            if(key.isReadable()){
                                read(key);
                            }
                        }catch (CancelledKeyException e){
                            //出现异常断开连接
                            key.cancel();
                        }
                        try{
                            //6、判断是否可写
                            if(key.isWritable()){
                                write(key);
                            }
                        }catch (CancelledKeyException e){
                            //出现异常断开连接
                            key.cancel();
                        }
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    private void write(SelectionKey key) {
        //清空缓存
        this.writeBuffer.clear();
        //获取当前通道对象
        SocketChannel channel = (SocketChannel) key.channel();
        //录入数据
        Scanner scanner = new Scanner(System.in);
        try {
            System.out.println("即将发送到客户端......");
            String line = scanner.nextLine();
            //把录入的数据写到Buffer中
            writeBuffer.put(line.getBytes("UTF-8"));
            //重置缓存游标
            writeBuffer.flip();
            channel.write(writeBuffer);
            channel.register(this.selector,SelectionKey.OP_READ);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    //使用通道读取数据
    private void read(SelectionKey key) {
        try{
            //清空缓存
            this.readBuffer.clear();
            //获取当前通道对象
            SocketChannel channel = (SocketChannel) key.channel();
            //将通道的数据(客户发送的data)读到缓存中
            int readLen = channel.read(readBuffer);
            //如果通道中没有数据
            if(readLen == -1){
                //关闭通道
                channel.close();
                //关闭连接
                key.cancel();
                return;
            }
            //Buffer中有游标,游标不会重置,需要我们调用flip重置,否则读取不一致
            this.readBuffer.flip();
            //创建有效字节长度数组
            byte[] bytes = new byte[readBuffer.remaining()];
            //读取buffer中数据保存在字节数组
            readBuffer.get(bytes);
            System.out.println("收到了从客户端:" + channel.getRemoteAddress() + " : " + new String(bytes,"UTF-8"));
            //注册通道,标记为写操作
            channel.register(this.selector,SelectionKey.OP_WRITE);
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    private void accept(SelectionKey key) {
        try{
            //1、当前通道在init方法中注册到了selector中的ServerSocketChannel
            ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
            //2、阻塞方法,客户端发起后请求返回
            SocketChannel channel = serverSocketChannel.accept();
            //3、serverSocketChannel设置为非阻塞
            channel.configureBlocking(false);
            //4、设置对应客户端的通道标记,设置此通道为可读时使用
            channel.register(this.selector,SelectionKey.OP_READ);
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

2、客户端

public class NIOClient {
    public static void main(String[] args) {
        //创建远程地址
        InetSocketAddress address = new InetSocketAddress("127.0.0.1",8888);
        SocketChannel channel = null;
        //定义缓存
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        try{
            //开启通道
            channel = SocketChannel.open();
            //连接远程服务器
            channel.connect(address);
            Scanner sc = new Scanner(System.in);
            while(true){
                System.out.println("客户端即将给 服务器发送数据......");
                String line = sc.nextLine();
                if(line.equals("exit")){
                    break;
                }
                //控制台输入数据写入缓存
                buffer.put(line.getBytes("UTF-8"));
                //重置游标
                buffer.flip();
                //数据发送到通道
                channel.write(buffer);
                //清空缓存数据
                buffer.clear();

                //读取服务器返回的数据
                int readLen = channel.read(buffer);
                if(readLen == -1){
                    break;
                }
                //重置buffer游标
                buffer.flip();
                byte[] bytes = new byte[buffer.remaining()];
                //读取数据到字节数组
                buffer.get(bytes);
                System.out.println("收到了服务器发送的数据:" + new String(bytes,"UTF-8"));
                buffer.clear();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

你可能感兴趣的:(RMI远程通信,java)