Netty 学习(八):新连接接入源码说明作者: Grey
原文地址:
博客园:Netty 学习(八):新连接接入源码说明
CSDN:Netty 学习(八):新连接接入源码说明
新连接的接入分为3个过程
- 检测到有新连接 。
- 将新连接注册到 worker 线程 。
- 注册新连接的读事件 。
NioEventLoop
中的processSelectedKey()
方法中private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {......final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();......// Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead// to a spin loopif ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {unsafe.read();}.....}
启动一个 Netty 服务端和 Netty 客户端,在unsafe.read()
这一行打断点,可以得到这里的unsafe
就是NioMessageUnsafe
, 进入NioMessageUnsafe
的read()
方法,这个方法主要做的事情就是:创建 , 设置并绑定
NioSocketChannel
。private final List<Object> readBuf = new ArrayList<Object>();@Overridepublic void read() {......do {// 创建`NioSocketChannel`int localRead = doReadMessages(readBuf);......} while (continueReading(allocHandle));......// 设置并绑定 NioSocketChannelint size = readBuf.size();for (int i = 0; i < size; i ++) {readPending = false;pipeline.fireChannelRead(readBuf.get(i));}readBuf.clear();allocHandle.readComplete();pipeline.fireChannelReadComplete();......}}
创建NioSocketChannel
调用的是doReadMessages()
方法 , 通过Debug , 可以看到doReadMessage()
来自于NioServerSocketChannel
中@Overrideprotected int doReadMessages(List<Object> buf) throws Exception {SocketChannel ch = SocketUtils.accept(javaChannel());try {if (ch != null) {buf.add(new NioSocketChannel(this, ch));return 1;}} catch (Throwable t) {logger.warn("Failed to create a new channel from an accepted socket.", t);try {ch.close();} catch (Throwable t2) {logger.warn("Failed to close a socket.", t2);}}return 0;}
可以看到此时调用的是 Java 底层的accept()
方法,创建了一条 JDK 层面的Channel
,Netty 将其封装成自定义的NioSocketChannel
, 并加入一个List
。继续 Debug,进入 NioSocketChannel 的构造方法中,调用的是
AbstractNioByteChannel
的构造方法protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) {super(parent, ch, SelectionKey.OP_READ);}
这个方法类似在 NIO 编程中,注册 OP_READ 事件,表示 Channel 对读事件感兴趣 。接下来是设置并绑定
NioSocketChannel
,处理每个NioSocketChannel
, 通过 Debug 可以来到AbstractUnsafe
的register0()
方法private void register0(ChannelPromise promise) {// 注册SelectordoRegister();// 执行 handlerpipeline.invokeHandlerAddedIfNeeded();// 传播 ChannelRegistered事件pipeline.fireChannelRegistered();// 注册读事件if (isActive()) {if (firstRegistration) {pipeline.fireChannelActive();} else if (config().isAutoRead()) {// This channel was registered before and autoRead() is set. This means we need to begin read// again so that we process inbound data.//// See https://github.com/netty/netty/issues/4805beginRead();}}}
这个方法主要完成的事情就是:- 将
NioSocketChannel
注册到Selector
上
- 配置自定义的
Handler
。
- 将连接注册事件传播下去,调用了每个
Handler
的channelRegistered
方法 。
- 注册读事件 。
本文所有图例见:processon: Netty学习笔记
更多内容见:Netty专栏
参考资料跟闪电侠学 Netty:Netty 即时聊天实战与底层原理
深度解析Netty源码
【八 Netty 学习:新连接接入源码说明】
推荐阅读
- 学习记录-Python的局部变量和全局变量
- 初等数论学习笔记 III:数论函数与筛法
- 前端程序员学习 Golang gin 框架实战笔记之一开始玩 gin
- 1 Libgdx游戏学习——环境配置及demo运行
- 苹果ipad分屏功能怎么使用(ipad 9可以分屏学习吗)
- Go设计模式学习准备——下载bilibili合集视频
- 学习ASP.NET Core Blazor编程系列五——列表页面
- 斗罗大陆:武魂觉醒荒野行纪第八章怎么过
- 七 Netty 学习:NioEventLoop 对应线程的创建和启动源码说明
- ZCTF note3:一种新解法