NIO模型及优化点

NIO

一:概述:

NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector(选择器)。传统IO是基于字节流和字符流进行操作(基于流),而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。

二:三者关系

1:一个线程对应一个Selector

2:一个Selector对应多个Channel

3:一个channel对应一个buffer

4:一个buffer是一个内存块(数组)

5:一个channel对应一个客户端连接

6:一个channel绑定一个端口,多个channel可以绑定同一个端口

三:NIO解决问题/存在问题

1:解决的问题

  1. :一个线程可以接收多个客户端连接

  2. :基于缓存,效率更高(BIO基于流)

  3. :不同的消息分发到不同的channel中

  4. :NIO解决的根本问题就是一个线程多个客户端

2:存在问题

1):若有消息处理太慢,其它channel消息会被卡住,同时其它客户端连接也无法接入。

三:代码演示

下面代码是两个selector,一个是连接selector,一个是读selector

package com.test.io;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NIOTest {

    public static void main(String[] args) throws Exception {
        //获取一个Selector
        Selector selector = Selector.open();
        /**
         * 创建一个连接类型的通道
         * 设置为不阻塞
         * 绑定端口6666
         * 注册到selector
         */
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.bind(new InetSocketAddress(6666));
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (true){
            /**
             * 未有连接或消息前阻塞在selector
             * 有消息后,继续执行
             */
            selector.select();

            /**
             * 获取消息中的SelectionKey的集合
             * 每次有消息过来都会有一个唯一对的SelectionKey添加到Selector中Set集合中
             * SelectionKey保存者channel信息
             */
            Set<SelectionKey> selectionKeys = selector.selectedKeys();//当前所有有消息的事件
            Iterator<SelectionKey> it = selectionKeys.iterator();
            while (it.hasNext()){//遍历所有消息事件,输出消息
                SelectionKey selectionKey = it.next();
                //获取到消息事件后,立即移除该消息事件
                selectionKeys.remove(selectionKey);
                //判断消息事件类型,是连接消息  还是普通消息
                if(selectionKey.isValid() && selectionKey.isAcceptable()){//连接消息
                    /**
                     * accept是一个阻塞方法,在此处基本不会阻塞,正是因为有消息才到达这里
                     * 为新的连接生成一个channel
                     * channel设置为不阻塞
                     * 注册到selector
                     */
                    SocketChannel channel = serverSocketChannel.accept();//与it.hasNext()一一对应,保证channel与SelectionKey对应
                    channel.configureBlocking(false);
                    channel.register(selector,SelectionKey.OP_READ);
                }
                if(selectionKey.isValid() && selectionKey.isReadable()){//普通消息
                    /**
                     * 获取消息的通道
                     */
                    SocketChannel channel = (SocketChannel) selectionKey.channel();
                    ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment();
                    channel.read(byteBuffer);
                    System.out.println("客户端消息:"+byteBuffer.toString());
                }
            }
        }
    }
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值