Netty源码剖析与实战-第四周

第三章:Netty 源码 从“线”(请求处理)的角度剖析

目录

第三章:Netty 源码 从“线”(请求处理)的角度剖析

Netty 代码编译与总览

编译Netty 常遇问题

Netty 源码核心包速览

启动服务

主线

知识点

构建连接

主线

知识点

接受数据

读数据技巧

主线


Netty 代码编译与总览

编译Netty 常遇问题

常见问题一:maven 插件会根据System.getProperties的内容生成对应依赖,如果是window32位无对应依赖

Netty源码剖析与实战-第四周

常见问题二:需先将netty-common包进行编译

Netty源码剖析与实战-第四周

Netty 源码核心包速览

Netty源码剖析与实战-第四周

 

 

启动服务

主线

Netty源码剖析与实战-第四周

知识点

启动服务的本质:
Selector selector = sun.nio.ch.SelectorProviderImpl.openSelector()  
ServerSocketChannel serverSocketChannel = provider.openServerSocketChannel() 
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
javaChannel().bind(localAddress, config.getBacklog());
selectionKey.interestOps(OP_ACCEPT);

Selector 是在new NioEventLoopGroup()(创建一批NioEventLoop)时创建。
第一次Register 并不是监听OP_ACCEPT,而是0:
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this) 。
最终监听OP_ACCEPT 是通过bind 完成后的fireChannelActive() 来触发的。
NioEventLoop 是通过Register 操作的执行来完成启动的。
类似ChannelInitializer,一些Hander 可以设计成一次性的,用完就移除,例如授权。

 

构建连接

主线

Netty源码剖析与实战-第四周

知识点

接受连接本质:
selector.select()/selectNow()/select(timeoutMillis) 发现OP_ACCEPT 事件,处理:
SocketChannel socketChannel = serverSocketChannel.accept()
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
selectionKey.interestOps(OP_READ);

 

创建连接的初始化和注册是通过pipeline.fireChannelRead 在ServerBootstrapAcceptor 中完成的。

第一次Register 并不是监听OP_READ ,而是0 :
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this) 。
最终监听OP_READ 是通过“Register”完成后的fireChannelActive
(io.netty.channel.AbstractChannel.AbstractUnsafe#register0中)来触发的
Worker’s NioEventLoop 是通过Register 操作执行来启动。
接受连接的读操作,不会尝试读取更多次(16次)。

 

接受数据

读数据技巧

1 自适应数据大小的分配器(AdaptiveRecvByteBufAllocator):
发放东西时,拿多大的桶去装?小了不够,大了浪费,所以会自己根据实际装的情况猜一猜下次情况,
从而决定下次带多大的桶。
2 连续读(defaultMaxMessagesPerRead):
发放东西时,假设拿的桶装满了,这个时候,你会觉得可能还有东西发放,所以直接拿个新桶等着装,
而不是回家,直到后面出现没有装上的情况或者装了很多次需要给别人一点机会等原因才停止,回家。

主线

• 多路复用器( Selector )接收到OP_READ 事件
• 处理OP_READ 事件:NioSocketChannel.NioSocketChannelUnsafe.read()
• 分配一个初始1024 字节的byte buffer 来接受数据
• 从Channel 接受数据到byte buffer
• 记录实际接受数据大小,调整下次分配byte buffer 大小
• 触发pipeline.fireChannelRead(byteBuf) 把读取到的数据传播出去
• 判断接受byte buffer 是否满载而归:是,尝试继续读取直到没有数据或满16 次;
否,结束本轮读取,等待下次OP_READ 事件
worker thread

 

备注:本文皆转自极客时间-netty源码剖析与实战,本人仅作整理和部分解读,用于记录和记忆留存!