前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >模仿echo命令学习NIO——Java实现

模仿echo命令学习NIO——Java实现

作者头像
MickyInvQ
发布2020-09-27 17:45:22
7970
发布2020-09-27 17:45:22
举报
文章被收录于专栏:InvQ的专栏InvQ的专栏InvQ的专栏

一、NIO模型:同步非阻塞IO处理

在传统的Java环境里面,最初的程序需要依赖于JVM虚拟机技术。最早的时候由于虚拟机的性能较差,所以很少有人去关注通讯的速度问题,大部分的问题都出现在了CPU处理上。 但是随着硬件的性能提升,实际上CPU的处理速度加强了。所以从JDK 1.4开始就引入NIO的开发包,可以带来底层数据的传输性能。 在NIO之中采用了一个Reactor事件模型,注册的汇集点Selector 【NIO】烧水,不会一直傻站着看,你采用轮询的方式来观察水是否烧开。

模型
模型

buffer

在这里插入图片描述
在这里插入图片描述

程序部分

首先创建一个服务端类:

public class NIOEchoServer {
    private static class EchoClientHandler implements Runnable {
        private SocketChannel clientChannel ; // 客户端通道
        private boolean flag = true ; // 循环处理标记
        public EchoClientHandler(SocketChannel clientChannel) {
            this.clientChannel = clientChannel ;
            // 严格意义上来讲,当已经成功的连接上了服务器,并且需要进行进一步处理之前要发送一些消息给客户端
        }
        @Override
        public void run() {
            ByteBuffer buffer = ByteBuffer.allocate(50) ; // 50个缓冲区
            try {
                while(this.flag) {  // 需要不断进行交互
                    buffer.clear() ;    // 清空缓冲区
                    int readCount = this.clientChannel.read(buffer) ; // 向缓冲区之中读取数据
                    String readMessage = new String(buffer.array(),0,readCount).trim() ;
                    String writeMessage = "【ECHO】" + readMessage + "\n" ; // 回应数据信息
                    if("byebye".equalsIgnoreCase(readMessage)) {
                        writeMessage = "【EXIT】拜拜,下次再见!" ;
                        this.flag = false ;
                     }
                     // 数据输入通过缓存的形式完成,而数据的输出同样需要进行缓存操作
                    buffer.clear() ; // 为了写入新的返回数据而定义
                    buffer.put(writeMessage.getBytes()) ; // 发送内容
                    buffer.flip() ; // 重置缓冲区
                    this.clientChannel.write(buffer) ;// 回应数据
                }
                this.clientChannel.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        // 1、NIO的实现考虑到性能的问题以及响应时间问题,需要设置一个线程池,采用固定大小的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        // 2、NIO的处理是基于Channel控制的,所以有一个Selector就是负责管理所有的Channel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 3、需要为其设置一个非阻塞的状态机制
        serverSocketChannel.configureBlocking(false); // 非阻塞模式
        // 4、服务器上需要提供有一个网络的监听端口
        serverSocketChannel.bind(new InetSocketAddress(HostInfo.PORT));
        // 5、需要设置一个Selector,作为一个选择器的出现,目的是管理所有的Channel
        Selector selector = Selector.open();
        // 6、将当前的Channel注册到Selector之中
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); // 连接时处理
        System.out.println("服务器已经启动成功,服务器的监听端口为:" + HostInfo.PORT);
        // 7、NIO采用的是轮询模式,每当发现有用户连接的时候就需要启动一个线程(线程池管理)
        int keySelect = 0; // 接收轮询状态
        while((keySelect = selector.select()) > 0) {    // 实现了轮询处理
            Set<SelectionKey> selectionKeys = selector.selectedKeys() ;   // 获取全部的Key
            Iterator<SelectionKey> selectionIter = selectionKeys.iterator() ;
            while(selectionIter.hasNext()) {
                SelectionKey selectionKey = selectionIter.next() ;  // 获取每一个Key的信息
                if (selectionKey.isAcceptable()) {  // 为连接模式
                    SocketChannel clientChannel = serverSocketChannel.accept() ; // 等待连接
                    if (clientChannel != null) {
                        executorService.submit(new EchoClientHandler(clientChannel)) ;
                    }
                }
                selectionIter.remove();
            }
        }
        executorService.shutdown();
        serverSocketChannel.close();
    }
}

客户端类

public class NIOEchoClient {
    public static void main(String[] args) throws Exception {
        SocketChannel clientChannel = SocketChannel.open() ; // 打开客户端连接通道
        clientChannel.connect(new InetSocketAddress(HostInfo.HOST_NAME,HostInfo.PORT)) ;// 连接
        ByteBuffer buffer = ByteBuffer.allocate(50) ;// 开辟缓冲区
        boolean flag = true ;
        while(flag) {
            buffer.clear() ; // 清空缓冲区
            String inputData = InputUtil.getString("请输入要发送的信息:").trim() ;
            buffer.put(inputData.getBytes()) ; // 将输入的数据保存在缓冲区之中
            buffer.flip() ; // 重置缓冲区
            clientChannel.write(buffer) ; // 发送数据
            buffer.clear() ; // 在读取之前进行缓冲区清空
            int readCount = clientChannel.read(buffer) ;
            buffer.flip() ;
            System.err.println(new String(buffer.array(),0,readCount));
            if("byebye".equalsIgnoreCase(inputData)) {
                flag = false ;
            }
        }
        clientChannel.close();
    }
}

程序测试

无论是采用之前的BIO(上一个博客)还是现在的NIO的client类,结果都是一样,因为我们搞事情,是搞在服务端,只要通过tcp进行通讯即可。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

相关

dubbo 服务提供者底层使用的是nio接受消费者的请求,在服务端使用多线程处理消费者端的io,阻塞与非阻塞是设置在服务端的,与客户端没关系。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-05-04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、NIO模型:同步非阻塞IO处理
  • buffer
  • 程序部分
  • 客户端类
  • 程序测试
  • 相关
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档