跳到正文
Elaine Blog
返回

从 Netty 源码理解启动与读写链路

网络与 I/O

读 Netty 源码的目标不是记住所有类,而是能回答:一个配置如何变成 Channel,一次就绪事件如何进入 Pipeline,一次写操作何时真正到达 Socket。 最有效的方法是带着可运行断点追一条主线。

Table of contents

Open Table of contents

准备最小调试入口

先运行Netty 编解码样例下载,确认协议层测试是绿色的。 源码调试再换成最小 Echo 服务器,固定 Netty 版本并下载对应 source JAR。不要一开始调试完整业务应用。

启动主线:配置如何落地

ServerBootstrap.bind() 开始,按以下问题记录调用链:

  1. 哪个 ChannelFactory 创建监听 Channel;
  2. Channel 何时注册到 EventLoop;
  3. option 和 Handler 何时应用;
  4. 底层 bind 何时执行;
  5. ChannelFuture 在哪里标记成功或失败。

异步 API 常见模式是:调用方拿到 Future,实际操作被提交到 EventLoop。断点看到“当前方法已经返回”不代表绑定或写入完成。

接受与读取主线

监听 Channel 收到接受事件后创建子 Channel,初始化它的 Pipeline,再注册到 worker EventLoop。子 Channel 读到字节时,底层 unsafe 层推进读循环, 分配 ByteBuf 并触发入站事件。

沿 fireChannelRead 查看 ChannelHandlerContext 如何寻找下一个入站 Handler。重点记录消息类型、引用计数和线程名,而不是复制几十层栈帧。

写入主线

write 把消息沿出站方向编码并加入出站缓冲区,flush 才推动已写消息交给底层传输。Socket 暂时不可写时,剩余数据必须保留,等下一次写就绪继续。 因此只调用 write 忘记 flush,或无界 writeAndFlush,分别会造成消息滞留和写队列膨胀。

观察 Promise 在成功写入、连接关闭和异常时如何完成。业务不能把“提交写操作”误当成“客户端已收到”。

一张可复查的阅读记录

每次源码阅读只输出四项:入口场景、关键对象、调用主线、验证断点。再补一个“如果这里变慢,会看到什么指标”的问题。

场景:子连接第一次读
入口:就绪事件
状态:Channel -> EventLoop -> Pipeline -> ByteBuf
验证:线程名固定;Handler 顺序与配置一致;消息最终释放

Netty 官方文档提供 4.2 的 API 与源码入口。阅读时版本必须与项目依赖一致,因为内部类名和实现细节会变化。

下一步

阅读手写轻量 RPC 框架,用协议、关联 ID、截止时间和服务调度组合一个完整调用链。


分享这篇文章:

上一篇
Netty 内存池、引用计数与泄漏排查
下一篇
手写轻量 RPC 框架:从调用假象到失败语义