Netty源码浅析

前言

到目前为止,已经看了不少框架的源码了,但如何对源码做笔记并写博客,不同框架适合的做笔记方式也不同

对于Netty框架而言,我认为以对比学习+回答问题的方式来浅析源码会好一些,因为Netty本质上也就是基于NIO的一个非阻塞网络编程框架,那么本篇笔记就对比一个简单的NIO非阻塞网络编程,看看Netty是如何实现的

流程解析

看Netty源码主要就是去看其如何实现Reactor模式的,关于Reactor的演变,在《初识Netty》中我做了对比,不进行赘述

本节主要比较一下NIO的传统非阻塞方式与Netty的多Reactor模式的区别

NIO传统非阻塞

在这里插入图片描述

Netty多Reactor

在这里插入图片描述

区别

Reactor一般就是指selector,在netty中,NioEventLoop既是一个单线程,又绑定了一个selector,绑定到selector上的Channel触发的IO事件都由NioEventLoop执行

  • Netty使用两种selector,一种负责处理accept,当有客户端请求ServerSocketChannel时,将对应的SocketChannel绑定到第二个selector中,第二种selector就负责处理绑定到自己身上的Channel对应的事件
  • 上述两个流程图虽然看上去改了很多,但核心代码段都是相同的(自己写一遍就知道),所以看源码的时候就对比着看

接下来,就通过NIO的非阻塞代码,看看Netty是怎么实现的

NIO网络编程例子

该例子来源于《尚硅谷的netty教程》

在注释中,我写明了每一步对应netty中的实现

public class NIOServer {
   
    public static void main(String[] args) throws IOException {
   
        // ServerBootstrap进行bind的时候,执行initAndRegistry会创建ServerSocketChannel
        // 并将ServerSocketChannel绑定到一个NioServerSocketChannel中
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);

        // NioEventLoop在构造方法进行初始化时,就会创建唯一一个selector
        Selector selector = Selector.open();
        
        // ServerBootstrap进行bind的时候,执行initAndRegistry
        // 会使用NioEventLoop来执行register进行异步注册
        // 并且注册时不会绑定任何事件
        // 直到bind监听好端口后,才会通过HeadContext该Handler通过执行ChannelActive方法将Accept事件绑定
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

       
        // ServerBootstrap在将SeverSocketChannel注册到selector后就会进行bin
        serverSocketChannel.socket().bind(new InetSocketAddress(6666));


        
		// NioEventLoop中执行run方法,进行循环
        while (true){
   
            
            // run方法中,如果队列中没有任务,则调用select进行阻塞
            if (selector.select(1000)==0){
   
                continue;
            }
            
            // 获取到事件,则执行processSelectedKeys来处理对应IO事件,整个流程大概就是如下逻辑
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
            
			// processSelectedKey对每个事件进行判断和处理
            while (keyIterator.hasNext()){
   

                SelectionKey key = keyIterator.next();
                // Accept事件只会在SeverSocketChannel中发生
                // 会在ServerBootstrapAcceptor的ChannelRead方法中完成下述过程
                // 该Handler在ServerBootstrap启动时就被加入Pipline中
                if (key.isAcceptable()){
   
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);
                    // 启动一个childEventLoop来执行注册逻辑
                    // 同样的,注册时没有绑定事件,事件由Head绑定
                    socketChannel.register(selector,SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                }
				// Read事件,触发NioByteUnsafe的read方法
                // 会将缓冲区的数据写入ByteBuffer,并传递到pipline中
                // 依次执行pipline中的handler的channelRead方法完成回调
                if (key.isReadable()) {
   
                    SocketChannel channel = (SocketChannel)key.channel();
                    ByteBuffer buffer = (ByteBuffer) key.attachment();
                    channel.read(buffer);
                }
                keyIterator.remove();
            }
        }

    }
}

根据注释,可以比较容易地去看懂netty整个框架怎么运作的

Netty源码

netty的源码大部分跟下来还是比较容易的,在本节主要根据前一节的注释中,一些不太好理解的方法进行浅析,以问答的形式

NioServerSocketChannel与ServerSocketChannel关系

  • NioServerSocketChannel是netty自定义的Channel类,其中绑定了Pipline,NioEventLoop等成员变量,但其网络功能,如bind,都要通过ServerSocketChannel来完成,因此NioServerSocketChannel会对应一个ServerSocketChannel
  • 我们知道,在使用select方法获取SelectionKeys时,只能从SelectionKey中获取到触发事件对应的NIO原生Channel,那NioServerSocketChannel该如何获取呢?方法就是注册的时候将NioServerSocketChannel作为ServerSocketChannel注册到selector的附件

相关代码在 AbstractNioChannel的doRegister()中

    @Override
    protected void doRegister() throws Exception {
   
        boolean selected = false
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值