JAVA网络编程:NIO

先来回顾一下BIO的特点:阻塞,主要体现以下点:

1.ServerSocket.accept()
2.InputStream.read(), OutputStream.write()
3.无法在同一个线程里处理多个I/O

有没有一种方法可以在一个线程内实现对多个IO的处理呢?

1.使用Channel代替Stream
2.使用Selector监控多条Channel
3.可以在一个线程里处理多个Channel I/O

Channel

在BIO模型中,Stream是单向的,有InputStream和OutputStream,NIO模型中的Channel是双向的,Channel的读/写是通过Buffer来实现的
在这里插入图片描述
下面是Channel的文档注释
在这里插入图片描述
大致意思就是,Channel就是I/O操作的纽带,表现在与实体的连接,例如硬件设备,文件,网络Socket或者程序组件(能够执行一种或多种不同的I/O操作,像读和写操作)。Channel有打开和关闭两种状态,在创建之后是open状态,Channel关闭之后就是closed状态,文末还特意提到Channel是线程安全的。

Buffer

Buffer就是内存里面一个数据的缓冲区,针对Channel的操作都离不开Buffer
在这里插入图片描述
文档第一句就说明Buffer是特定原始类型数据的容器,buffer是特定原始类型元素的线性有限序列。 除了内容之外,buffer的基本属性是其容量(capacity),限制(limit)和位置(position)
下面是buffer缓冲区的一些结构图和操作模式
在这里插入图片描述
进入读取模式读取数据时候,这里分为两种情况:①数据全部读取完毕 ②读取部分数据时转换为写模式
在这里插入图片描述
在这里插入图片描述
Channel之间可以互相传递数据
在这里插入图片描述
Channel说到底还是读写数据的通道,那现在还是没有解决根本问题,一个线程处理多个I/O请求

Selector

Channel注册在Selector上,Selector监控着所有的Channel
在这里插入图片描述
注册完一个Channel之后,就会得到一个与Channel对应的SelectionKey
而每一个SelectionKey对应都有一下几个方法
interestOps:当前Channel有哪些感兴趣的状态(一个或多个)
readyOps:目前有哪些状态可操作
channel:返回SelectionKey所指代的注册的Channel对象
selector:在哪个Selector对象上面完成注册
attachment: 返回Channel附属上的对象
在这里插入图片描述
下面用NIO来写一个服务端的聊天

class ServerNIO {

    public static void main(String[] args) throws IOException {
        //创建ServerSocket服务
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        //设置为非阻塞
        serverSocket.configureBlocking(false);
        //绑定端口
        serverSocket.socket().bind(new InetSocketAddress(7000));

        //打开一个通道管理器
        Selector selector = Selector.open();
        //将ServerSocket注册到selector中,给它一个SelectionKey.OP_ACCEPT
        serverSocket.register(selector, SelectionKey.OP_ACCEPT);

        while (true){
            selector.select();
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

            while(iterator.hasNext())
            {
                SelectionKey key = iterator.next();

                if(key.isAcceptable()){
                    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);
                    System.out.println("有新的连接进来");
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    iterator.remove();

                }else if(key.isReadable()){
                    SocketChannel channel = (SocketChannel) key.channel();
                    //处理业务
                    handle(channel);
                }
            }
        }

    }

    private static void handle(SocketChannel channel) throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        int read = channel.read(byteBuffer);

        if(read > 0){
            System.out.println(new String(byteBuffer.array(), 0, read));

            channel.write(ByteBuffer.wrap("success\n".getBytes()));
        }

    }

}

可以看到使用NIO之后即使没有使用多线程,单线程也可以处理两个客户端的请求
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值