NIO模式的IO多路复用底层原理

上一篇 <<<BIO模型的缺陷
下一篇 >>>select、poll、epoll的区别


产生缘由

因为BIO存在线程阻塞,伪异步的话也会存在线程安全和资源浪费情况,而NIO恰好能解决这些问题。

底层原理关键词

面向与缓冲区
基于通道实现非阻塞式io
多路io复用实现(选择器)

通道(Channel)----TCP链接道路
通常我们nio所有的操作都是通过通道开始的,所有的通道都会注册到统一个选择器(Selector)上实现管理,在通过选择器将数据统一写入到 buffer中。
缓冲区(Buffer)------加快数据的读取
Buffer本质上就是一块内存区,可以用来读取数据,也就先将数据写入到缓冲区中、在统一的写入到硬盘上。
选择器(Selector)------通道的管理,实现多路IO复用机制---一个线程处理多个TCP请求。
Selector可以称做为选择器,也可以把它叫做多路复用器,可以在单线程的情况下可以去维护多个Channel,也可以去维护多个连接;
线程--完成具体的业务

Nio技术多路IO复用底层实现原理

多路:实际指的就是多个不同的tcp连接
复用:一个线程可以维护多个不同的io操作
好处: 占用cpu资源非常小、保证线程安全问题

手写伪NIO代码

public class SocketNioTcpServer {
    private static List<SocketChannel> listSocketChannel = new ArrayList<>();
    private static ByteBuffer byteBuffer = ByteBuffer.allocate(512);

    public static void main(String[] args) {
        try {
            // 1.创建一个ServerSocketChannel
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            // 2. 绑定地址
            ServerSocketChannel bind = serverSocketChannel.bind(new InetSocketAddress(9090));
            serverSocketChannel.configureBlocking(false);
            while (true) {
                /**channel管道:TCP数据传输的通道*/
                SocketChannel socketChannel = serverSocketChannel.accept();
                if (socketChannel != null) {
                    /**通道加入到选择器中*/
                    socketChannel.configureBlocking(false);
                    listSocketChannel.add(socketChannel);
                }
                /**轮询选择器下的所有通道信息,利用buffer缓存机制读取数据*/
                for (SocketChannel scl : listSocketChannel) {
                    try {
                        int read = scl.read(byteBuffer);
                        if (read > 0) {
                            byteBuffer.flip();
                            Charset charset = Charset.forName("UTF-8");
                            String receiveText = charset.newDecoder().decode
                                    (byteBuffer.asReadOnlyBuffer()).toString();
                            System.out.println(Thread.currentThread().getName()+" receiveText:" + receiveText);
                        }
                        listSocketChannel.remove(scl);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

推荐阅读:
<<<OSI七层模型与层上协议
<<<TCP的三次握手建立链接和四次挥手释放链接
<<<TCP、UDP及Socket代码示例
<<<Https的1.0、2.0协议及长短链接区别
<<<Linux系统的五种IO模型
<<<BIO和NIO区别
<<<BIO模型的缺陷
<<<select、poll、epoll的区别
<<<Redis为什么单线程能够支持高并发
<<<Netty初识
<<<Netty的粘包和拆包问题分析
<<<粘包和拆包问题解决方案汇总
<<<序列化与反序列化知识点汇总
<<<MessagePack反序列化使用示例
<<<Marshalling在Netty中的使用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容