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 对读事件感兴趣 。【八 Netty 学习:新连接接入源码说明】接下来是设置并绑定
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
方法 。经验总结扩展阅读
- 紫妈是什么意思
- 高中物理好的学习方法
- 学习记录-Python的局部变量和全局变量
- 如何让差生学习好英语
- 2022年腊月初八乔迁新居好吗
- 初等数论学习笔记 III:数论函数与筛法
- 为什么有些人会孤立认真学习的人
- 为什么西晋会发生八王之乱
- 苹果ipad分屏功能怎么使用(ipad 9可以分屏学习吗)
- 前端程序员学习 Golang gin 框架实战笔记之一开始玩 gin