前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Bio、Nio、Aio的用法系列之NIO服务端(二)

Bio、Nio、Aio的用法系列之NIO服务端(二)

作者头像
用户1257393
发布2018-07-30 15:04:52
2910
发布2018-07-30 15:04:52
举报
文章被收录于专栏:精讲JAVA精讲JAVA

NIO的由来

技术圈有很多人说NIO是new IO,是因为他是新增的接口,这也是官方说法,但是,我们知道,以前都是阻塞IO,详细见上文BIO详解,而NIO是非阻塞的,所以说,NIO更确切的说法 是non-block IO,当然关于说法,大家可以根据自己的理解,不过多做解释。 首先在讲解NIO之前我们先了解几个概念

1、缓冲区Buffer

Buffer是一个对象,在nio读取数据时,他是直接读到buffer的,写数据时,也是先写到缓冲区的,所以任何时候访问,都是通过缓冲区完成的, Buffer的实质是一个数据,一般来说是一个字节数据,byteBuffer,也可以是其他的数组,但是缓冲区不是一个简简单单的数组,缓冲区对数据的结构化访问以及维护读写位置信息

2、通道Channel

管道是一个管道,是全双工模式,对于里面的数据,可读可写,比流更好的映射到底层操作系统的API,支持同时读写操作,Channel一共可以分为两大类,一个是SelectableChannel,一个是FileChannel,不过本例中并没有用到FileChannel,因为SocketChannel跟ServerSocketChannel都是SelectableChannel的子类

NIO服务端的代码实现

1、服务端启动器

代码语言:javascript
复制
public class NioServer {
    public static void main(String [] args){
        //启动一个线程
        new Thread(new NioServerHandle()).start();
    }
}

2、NioServerHandle构造器中初始化

代码语言:javascript
复制
    //初始化注册
    public NioServerHandle(){
        try {
            //获取ServerSocketChannel对象
            serverSocketChannel = ServerSocketChannel.open();
            //绑定ip
            serverSocketChannel.socket().bind(new InetSocketAddress("127.0.0.1",8989));
            //设置为非阻塞
            serverSocketChannel.configureBlocking(false);
            //获取Selector
            selector = Selector.open();
            //将管道注册到多路复用器selector上
            serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

3、run方法中进行轮询

代码语言:javascript
复制
@Override
    public void run() {
        //轮询key
        while (!stop){
            try {
                //设置超时时间
                selector.select(1000);
                //获取所有key
                Set<selectionkey> selectionKeys = selector.selectedKeys();
                //遍历
                Iterator</selectionkey><selectionkey> it = selectionKeys.iterator();
                SelectionKey selectionKey = null;
                while (it.hasNext()){
                    selectionKey = it.next();
                    //获取到就绪数组进行操作,并移除
                    it.remove();
                    try {
                        handle(selectionKey);
                    }catch (Exception e){
                        selectionKey.cancel();
                        selectionKey.channel().close();
                    }

                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

4、处理客户端发送过来的请求

代码语言:javascript
复制
    /**
     * 处理
     * @param key
     * @throws Exception
     */
    public void handle(SelectionKey key) throws Exception{
        if (key.isValid()){
            if (key.isAcceptable()){
                //获取ServerSocketChannel
                ServerSocketChannel ssc = (ServerSocketChannel)key.channel();
                //接受请求
                SocketChannel sc = ssc.accept();
                //设置为非阻塞
                sc.configureBlocking(false);
                //注册到多路复用器
                sc.register(selector,SelectionKey.OP_READ);
            }
            //read data
            if (key.isReadable()){
                //得到SocketChannel
                SocketChannel sc = (SocketChannel) key.channel();
                //设置字节缓冲区
                ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                //将通道的数据读取码流
                int readByte = sc.read(readBuffer);
                //对于大于0的情况进行编解码
                if (readByte > 0){
                    //将当前的缓冲区的limit设置为0,让后面进行读取
                    readBuffer.flip();
                    //根据缓冲区的可读大小设置字节数组
                    byte [] bytes = new byte[readBuffer.remaining()];
                    //get将读取的数据放入字节数组
                    readBuffer.get(bytes);
                    //将字节数组按照UTF-8的格式输出到body
                    String body = new String(bytes,"UTF-8");
                    System.out.print("The Time server recevive order:"+body);
                    String currentTime = "query".equals(body)?new java.util.Date(System.currentTimeMillis()).toString():"No";
                    //进行输出操作
                    doWrite(sc,currentTime);
                }else if (readByte < 0 ){
                    key.cancel();
                    sc.close();
                }else {
                }
            }
        }
    }
</code>

5、将数据返回给客户端

代码语言:javascript
复制
    /**
     * 将数据返回给客户端
     * @param sc
     * @param currentTime
     * @throws Exception
     */
    public void doWrite(SocketChannel sc,String currentTime) throws Exception{
        if (currentTime != null && currentTime.trim().length() > 0){
            //转换为字节数组,放到缓冲区
            byte [] bytes = currentTime.getBytes();
            ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
            byteBuffer.put(bytes);
            byteBuffer.flip();
            sc.write(byteBuffer);
        }
    }
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-05-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 精讲JAVA 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • NIO的由来
  • 1、缓冲区Buffer
  • 2、通道Channel
    • NIO服务端的代码实现
    • 1、服务端启动器
    • 2、NioServerHandle构造器中初始化
    • 3、run方法中进行轮询
    • 4、处理客户端发送过来的请求
    • 5、将数据返回给客户端
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档