0
点赞
收藏
分享

微信扫一扫

netty源码解读五(channel消息处理)

Gaaidou 2022-04-04 阅读 71
nettyjava

channel消息处理

从SingleThreadEventExecutor#run方法中找到processSelectedKeys方法。

服务端channel(包含客户端channel注册等)

processSelectedKey方法中,服务端对accept事件感兴趣, unsafe.read()方法会走NioMessageUnsafe#read()方法,做两件事,一件是拿到客户端channel后封装成NioSocketChannel加进list集合,另一件是遍历list集合,将每个客户端channel传递到服务端pipeline中,执行客户端channel注册,客户端pipeline的初始化,客户端channel激活等;
1)首先执行doReadMessages方法,其中调用jdk的ServerSocketChannel的accept方法,拿到SocketChannel,再封装成NioSocketChannel,此处执行了NioSocketChannel的两参数构造方法,执行逻辑和服务端channel几乎一致,接着将每个NioSocketChannel加入List集合;
2)接着遍历List集合, 执行pipeline.fireChannelRead(xxx),将每个NioSocketChannel传入到服务端通道,目前服务端通道是HeadContext<——>配置的handler<——>ServerBootstrapAcceptor<——>TailContext;这里fireChannelRead方法主要在ServerBootstrapAcceptor中实现;首尾均未实现。
3)接着进入到ServerBootstrapAcceptor#channelRead方法,其中主要做两件事一是添加,二是注册;添加指的是拿到客户端channel,向客户端pipeline中添加一个ChannelInitializer实例(在注册之前先往pipeline中添加ChannelInitializer实例,这个客户端channel和服务端channel一样,服务端是在initAndRegister方法中的init方法中往服务端pipeline中添加CI实例的),这个实例是在配置ServerBootstrap中通过建造者设计模式保存在childHandler属性中的,另外也会将ChannelInitializer实例加入到单向链表中,方便后续取出ChannelInitializer实例执行initChannel方法;注册指的是向workGroup的nioEventLoop的selector中注册NioSocketChannel以及处理上一步添加的ChannelInitializer实例,大体逻辑和服务端socket注册一致,但客户端channel注册会调用NioByteUnsafe类的register方法(服务端channel调用的是NioMessageUnsafe类的方法),最终和服务端channel注册一样都会调用父类AbstractUnsafe的register方法,还有一个区别是服务端的绑定和激活是在异步任务4中执行的,但客户端没有绑定,并且激活是在注册之后紧接着执行,并且激活目的是让selector监听read事件。注册的具体逻辑如下:
3.1)next方法从workerGroup组中取出一个NioEventLoop实例执行register方法,最终调用的是AbstractUnsafe#register方法;
3.2)向当前workerGroup的NioEventLoop实例中提交一个异步任务:register0;这个方法与服务端channel注册的方法是同一个方法;
3.2.1)doRegister(),将NioSocketChannel注册到workerGroup中nioEventLoop的selector上;
3.2.2)pipeline.invokeHandlerAddedIfNeeded(),回调在ServerBootstrapAcceptor#channelRead中添加到客户端pipeline中的ChannelInitializer,执行其中的initChannel方法,完成对客户端pipeline的初始化,即向客户端pipeline中添加处理器;
3.2.3)safeSetSuccess(promise),设置promise成功;
3.2.4)pipeline.fireChannelRegistered(),传播注册,可以在自定义Handler中实现该方法;
3.2.5)pipeline.fireChannelActive(),激活客户端channel所注册的selector,对read事件感兴趣;在服务端channel注册时,由于isActive方法返回false,所以不会在这里执行到fireChannelActive方法,而是在绑定完成后激活的,但客户端channel注册后,isActive方法就返回true,所以会执行激活方法;

客户端channel

processSelectedKey方法中,客户端对read事件感兴趣, unsafe.read()方法会走NioByteUnsafe#read()方法;所以NioMessageUnsafe#read()是用于建立客户端channel和初始化客户端pipeline,而NioByteUnsafe#read()是在已经建立好客户端channel基础上进行数据的读;
1)NioSocketChannel#doReadBytes(…) 读取客户端socket缓冲区数据;
2)NioSocketChannel#pipeline.fireChannelRead(byteBuf) 向客户端通道传播 ByteBuf 数据;
3)NioSocketChannel#pipeline.fireChannelReadComplete() 向客户端通道传播 “读完成” 事件;

ServerBootStrap

保存配置信息到启动类中,主要包括group,channel,option,handler,childHandler;
1)创建NioEventLoopGroup实例分别作为bossGroup,workGroup;
2)设置服务端Channel类型为NioServerSocketChannel;
3)保存一些server端自定义选项option;
4)配置Server端自定义的pipeline处理器,保存一个与日志相关的ChannelHandle实例到handle属性,第二次初始化服务端pipeline时候使用;
5)配置客户端pipeline的ChannelInitializer,其中包含initChannel方法,这是个回调方法,用于初始化客户端pipeline,这里只是配置,并没有加到客户端pipeline中。保存一个ChannelInitializer实例到childHandler属性,在ServerBootstrapAcceptor#channelRead方法中,会将childHandler加入到客户端pipeline中,用于后续初始化客户端pipeline;

举报

相关推荐

0 条评论