本页是《Java 网络编程基础》的目录与学习路径。全书 50 篇:15 章 45 节,加序、前言、本页目录和两个附录。主线是把
linkd从一个阻塞 echo 服务器写到最小网关:每一个协议结论都要落到一个类、一条命令或一次抓包上。
这本书回答什么
Java 四卷本把 library 写成了 libraryd,但请求从网卡到方法之间的那一层,一直由框架代劳。本书把这一层打开,按五个问题组织:
- 一次请求从网卡到 Java 方法,中间经过哪些缓冲区、线程与系统调用。
- BIO、NIO、Selector、Reactor 的差别在哪里,什么场景该用哪一种。
- 半包、粘包、背压、超时、优雅关闭这些工程问题,怎么在代码里解决。
- HTTP/1.1、HTTP/2、TLS、WebSocket 的协议边界与最小实现。
- 怎么用
tcpdump、netstat、lsof、ab、JFR 证明结论,而不是背结论。
这五个问题对应五个部分:地图与语义、字节与事件循环、协议实现、运行时工程、验证与收口。每一部分都以 linkd 的可运行代码收尾,而不是停在概念图。
全书概览
| 项目 | 内容 |
|---|---|
| 书稿 | 《Java 网络编程基础》 |
| 篇数 | 50 篇(15 章 45 节 + 序、前言、目录 + 附录 A/B) |
| 领域 | Java 网络编程、NIO、协议实现、网关工程 |
| 贯穿项目 | linkd —— 从阻塞 echo 到 linkd v1 网关 |
| 主线版本 | JDK 25 LTS(Temurin 25.0.5+8)、Maven 3.9.12 |
| 实验依赖 | 仅 JDK 标准库;测试用 JUnit Jupiter 5.14.4 |
| 机器口径 | Apple M1 Pro,10 核,32 GB,macOS 26.3 (25D125) |
| 上游服务 | libraryd,http://127.0.0.1:8080 |
| 上级专题 | 书稿专题 |
三条学习路径
全书按章顺序读最完整,但真实工作通常从一个目标、一个症状或一个项目阶段开始。下面三条路径可以跳读,路径里的每一篇都指向具体小节。
路径一:按目标
目标 A:写一个非阻塞服务器。 适合要把 NIO 真正用起来、而不是只记住 API 的读者。
- 1.1 从一次 HTTP 请求看 Java 网络栈 :先知道字节经过哪些层。
- 1.2 BIO、NIO、AIO 与 Reactor 模型 / 1.3 linkd 项目与实验环境 :选模型、搭骨架。
- 2.1 TCP 连接、字节流与可靠性边界 / 3.1 Socket 与 ServerSocket 基本用法 / 3.2 连接、读、写超时 :先把阻塞版本写对。
- 4.2 定长、分隔符与长度域帧 :消息边界从哪里来。
- 5.1 Buffer 的 position、limit 与 flip / 5.2 DirectBuffer 与堆外内存 :读写索引与内存类型。
- 6.1 Selector 就绪事件与 interestOps / 6.2 单线程 Reactor 实现 :事件循环的最小闭环。
- 7.1 非阻塞 accept、read 与 write / 7.2 半包、粘包与缓冲区增长 / 7.3 连接状态机与空闲检测 :把服务器写成能用的样子。
- 12.1 事件循环与任务队列 / 14.1 读写水位与背压信号 / 14.3 优雅关闭与连接排空 :线程、背压与关闭。
目标 B:读懂并实现协议。 适合要做网关、RPC、长连接或协议改造的读者。
- 2.1 TCP 连接、字节流与可靠性边界 / 4.1 字节序、字符集与边界 / 4.2 定长、分隔符与长度域帧 :协议的最小材料。
- 8.1 请求行、头部与消息体 → 8.2 keep-alive、chunked 与管线化 → 8.3 路由、静态文件与错误响应 :HTTP/1.1 全链路。
- 9.1 HTTP/2 帧类型与流状态 → 9.2 HPACK 与头部压缩 → 9.3 多路复用、流量控制与优先级 :HTTP/2 的三个核心机制。
- 10.1 TLS 1.3 握手与证书链 / 10.2 SSLEngine 非阻塞握手 :加密层怎么接进事件循环。
- 11.1 WebSocket 握手与 Upgrade / 11.2 帧格式、掩码与分片 :长连接消息协议。
目标 C:排障与压测。 适合线上已经出问题、需要先定位的读者。
- 15.1 tcpdump、netstat 与连接诊断 :先看连接状态和包。
- 15.2 压测工具与指标口径 :吞吐、分位、错误数一起看。
- 3.3 半关闭、RST 与优雅关闭 / 14.2 超时、重试与幂等边界 :解释连接为什么断。
- 14.3 优雅关闭与连接排空 / 15.3 linkd v1 验收与故障复盘 :把修复变成验收项。
路径二:按症状
症状一:连不上,或连上立刻断。
先看 2.3 InetAddress、端口与网络接口
确认绑定地址,再看 3.1 Socket 与 ServerSocket 基本用法
的 accept 与 backlog,随后用 3.2 连接、读、写超时
区分连接超时与读超时,最后用 15.1 tcpdump、netstat 与连接诊断
看握手停在哪一步。如果连接是被对端重置的,补 3.3 半关闭、RST 与优雅关闭
。
症状二:请求卡住,或响应被截断。
先看 7.2 半包、粘包与缓冲区增长
,确认是不是把一次 read 当成一条消息;再看 8.1 请求行、头部与消息体
的 Content-Length 与消息体边界;长连接场景补 8.2 keep-alive、chunked 与管线化
。写不出去时看 14.1 读写水位与背压信号
,超时与重试看 14.2 超时、重试与幂等边界
。
症状三:吞吐上不去,CPU 却很闲。
先判断模型是否选错:1.2 BIO、NIO、AIO 与 Reactor 模型
,再看 6.1 Selector 就绪事件与 interestOps
是否漏注册 OP_WRITE,6.2 单线程 Reactor 实现
是否被业务阻塞,12.2 业务线程池与阻塞隔离
是否把慢任务留在了事件循环,最后用 15.2 压测工具与指标口径
复核连接数与分位。
症状四:内存持续上涨,怀疑堆外泄漏。
先看 5.2 DirectBuffer 与堆外内存 的分配与回收,再看 13.2 DirectByteBuffer 分配与回收 的 Cleaner 与上限,文件传输场景补 13.3 内存映射与文件传输 。用 15.2 压测工具与指标口径 记录压测前后的常驻内存。
症状五:发布重启时丢少量请求。
先看 3.3 半关闭、RST 与优雅关闭 理解关闭时的 RST,再看 14.3 优雅关闭与连接排空 的停止 accept、排空写队列和期限,最后用 15.3 linkd v1 验收与故障复盘 把「发布不丢请求」写成验收项。
症状六:TLS 握手失败,或 ALPN 协商不到 h2。
按顺序看 10.1 TLS 1.3 握手与证书链
的证书与 SAN、10.2 SSLEngine 非阻塞握手
的状态机、10.3 会话复用、ALPN 与证书校验
的协议选择。证书问题先用 curl -v 和 keytool -list 确认,不要先改 Java 代码。
路径三:按项目
如果你只想看 linkd 怎么长起来,按阶段走:
| 阶段 | 目标 | 小节 |
|---|---|---|
| 0 骨架 | 四模块能编译,端口能起 | 1.1 、1.3 |
| 1 阻塞 echo | 一个连接一个线程,先跑通 | 2.1 、3.1 、3.2 、3.3 |
| 2 帧与缓冲 | 消息有边界,缓冲区可复用 | 4.1 、4.2 、4.3 、5.1 、5.2 |
| 3 单线程 Reactor | 一个线程管多连接 | 6.1 、6.2 、7.1 、7.2 、7.3 |
| 4 HTTP/1.1 | 能响应 curl,能路由 | 8.1 、8.2 、8.3 |
| 5 协议扩展 | HTTP/2、TLS、WebSocket | 9.1 、9.2 、9.3 、10.1 、10.2 、10.3 、11.1 、11.2 、11.3 |
| 6 运行时工程 | 线程、内存、背压、关闭 | 12.1 、12.2 、12.3 、13.1 、13.2 、13.3 、14.1 、14.2 、14.3 |
| 7 验收 | 抓包、压测、复盘 | 15.1 、15.2 、15.3 |
前置三篇与附录
| 篇目 | 作用 |
|---|---|
| 序:为什么要从 Socket 写到网关 | 四卷本之后的空白、读者画像、三卷路线与实验纪律 |
| 前言 | 版本口径、macOS 平台事实、代码约定、验证方法与内容边界 |
| 目录与学习路径 | 本页;全书 50 篇的入口与三条路径 |
| 附录 A Socket 与 NIO API 速查 | Socket、ServerSocket、Channel、Buffer、Selector 的常用方法 |
| 附录 B 网络诊断命令清单 | netstat、lsof、tcpdump、ab、jcmd 的可复制命令 |
十五章一览
第一部分:地图、语义与连接(第 1–3 章)
| 章 | 节 | 核心内容 |
|---|---|---|
| 1 网络编程地图与实验环境 | 1.1 从一次 HTTP 请求看 Java 网络栈 | 请求路径、内核缓冲区、accept 队列、Java 可见边界 |
| 1.2 BIO、NIO、AIO 与 Reactor 模型 | 阻塞/非阻塞、就绪/完成、单线程与主从 Reactor | |
| 1.3 linkd 项目与实验环境 | 四模块骨架、LinkdMain、端口与诊断命令 | |
| 2 TCP/UDP 语义与 Java API | 2.1 TCP 连接、字节流与可靠性边界 | 三次握手、四次挥手、字节流无边界、可靠性不等于低延迟 |
| 2.2 UDP 数据报、MTU 与丢包 | DatagramSocket、MTU、分片、应用层重传 | |
| 2.3 InetAddress、端口与网络接口 | 地址解析、NetworkInterface、绑定地址与回环 | |
| 3 Socket、超时与连接生命周期 | 3.1 Socket 与 ServerSocket 基本用法 | accept、读写、backlog、一个连接一个线程 |
| 3.2 连接、读、写超时 | connect 超时、SO_TIMEOUT、写超时为何不存在 | |
| 3.3 半关闭、RST 与优雅关闭 | shutdownOutput、RST 触发条件、SO_LINGER |
第二部分:字节与事件循环(第 4–7 章)
| 章 | 节 | 核心内容 |
|---|---|---|
| 4 字节、缓冲区与编解码基础 | 4.1 字节序、字符集与边界 | ByteOrder、UTF-8、CharsetDecoder、截断字符 |
| 4.2 定长、分隔符与长度域帧 | 三种成帧、最大长度、半包与多帧 | |
| 4.3 编解码器设计与错误处理 | 编解码器接口、异常策略、FrameDecoder | |
| 5 NIO Buffer 与 Channel | 5.1 Buffer 的 position、limit 与 flip | 三值状态、flip/clear/compact、读写切换 |
| 5.2 DirectBuffer 与堆外内存 | 分配成本、Cleaner、堆内与堆外对照 | |
| 5.3 FileChannel、Scatter/Gather 与零拷贝 | transferTo、readv/writev、适用边界 | |
| 6 Selector 与单线程事件循环 | 6.1 Selector 就绪事件与 interestOps | OP_ACCEPT/READ/WRITE、select、wakeup |
| 6.2 单线程 Reactor 实现 | register、事件分发、读写回调 | |
| 6.3 多线程 Reactor 与主从模型 | boss/worker、跨线程注册、负载分配 | |
| 7 非阻塞服务器与半包处理 | 7.1 非阻塞 accept、read 与 write | configureBlocking(false)、返回 0 与 -1、写半包 |
| 7.2 半包、粘包与缓冲区增长 | 累积缓冲、上限、压缩与扩容 | |
| 7.3 连接状态机与空闲检测 | 连接状态、lastRead、定时扫描与关闭 |
第三部分:协议实现(第 8–11 章)
| 章 | 节 | 核心内容 |
|---|---|---|
| 8 手写 HTTP/1.1 服务器 | 8.1 请求行、头部与消息体 | 请求行解析、头部大小限制、Content-Length |
| 8.2 keep-alive、chunked 与管线化 | 连接复用、chunk 解码、响应顺序 | |
| 8.3 路由、静态文件与错误响应 | HttpRouter、/healthz、404/500 与静态文件 | |
| 9 HTTP/2 帧与多路复用 | 9.1 HTTP/2 帧类型与流状态 | 9 字节帧头、SETTINGS、流状态机 |
| 9.2 HPACK 与头部压缩 | 静态表、动态表、Huffman、整数编码 | |
| 9.3 多路复用、流量控制与优先级 | stream ID、WINDOW_UPDATE、优先级取舍 | |
| 10 TLS/SSLEngine 与非阻塞握手 | 10.1 TLS 1.3 握手与证书链 | 1-RTT、keytool、证书链与 SAN |
| 10.2 SSLEngine 非阻塞握手 | wrap/unwrap、NEED_TASK、握手状态 | |
| 10.3 会话复用、ALPN 与证书校验 | session ticket、ALPN h2、主机名校验 | |
| 11 WebSocket 协议与帧处理 | 11.1 WebSocket 握手与 Upgrade | Sec-WebSocket-Key、101、协议切换 |
| 11.2 帧格式、掩码与分片 | opcode、mask、continuation、控制帧 | |
| 11.3 心跳、关闭与广播 | ping/pong、关闭码、会话表与广播 |
第四部分:运行时工程(第 12–14 章)
| 章 | 节 | 核心内容 |
|---|---|---|
| 12 Reactor 线程模型 | 12.1 事件循环与任务队列 | execute、任务队列、禁止阻塞事件循环 |
| 12.2 业务线程池与阻塞隔离 | 池大小、队列、拒绝策略、虚拟线程对照 | |
| 12.3 上下文传播与线程安全 | ThreadLocal、ScopedValue、不可变消息 | |
| 13 零拷贝与 DirectByteBuffer | 13.1 零拷贝的系统调用边界 | sendfile/mmap 的 JDK 抽象与适用条件 |
| 13.2 DirectByteBuffer 分配与回收 | Cleaner、MaxDirectMemory、池化 | |
| 13.3 内存映射与文件传输 | MappedByteBuffer、transferTo、静态文件 | |
| 14 背压、超时与优雅关闭 | 14.1 读写水位与背压信号 | 高/低水位、暂停读、队列上限 |
| 14.2 超时、重试与幂等边界 | 超时分层、重试放大、幂等键 | |
| 14.3 优雅关闭与连接排空 | SIGINT、停止 accept、排空、关闭期限 |
第五部分:验证与收口(第 15 章)
| 章 | 节 | 核心内容 |
|---|---|---|
| 15 抓包、压测与故障定位 | 15.1 tcpdump、netstat 与连接诊断 | lo0 抓包、连接状态、fd 与端口 |
| 15.2 压测工具与指标口径 | ab、吞吐/分位、协调缺失、Little’s law | |
| 15.3 linkd v1 验收与故障复盘 | 验收清单、故障注入、复盘模板 |
项目状态
linkd 按章增量生长,不要求每节都从零开始。下表是每章结束时的项目状态,读某一节前可以对照,确认代码基线。
| 章 | linkd 状态 |
|---|---|
| 1 | 四模块骨架、LinkdMain、GET /healthz 占位响应、环境脚本 |
| 2 | TCP/UDP 探针实验;地址绑定与网络接口观察 |
| 3 | 阻塞 echo 服务器;连接超时、读超时、半关闭与 RST 对照 |
| 4 | FrameDecoder 的定长、分隔符、长度域三种实现与单元测试 |
| 5 | BufferPool 初版;堆内/堆外缓冲对照;FileChannel 静态文件实验 |
| 6 | 单线程 EventLoop;Handler 接口;Selector 注册与事件分发 |
| 7 | 非阻塞 accept/read/write;Connection 状态机;空闲检测 |
| 8 | HttpParser、HttpRouter;/healthz 与 /books/{id} 固定响应 |
| 9 | HTTP/2 帧编解码、HPACK 解码、流表与流量控制(教学实现) |
| 10 | SSLEngine 握手封装;证书校验;ALPN 选择 |
| 11 | WebSocketFrame、WebSocketSession;/ws/echo 与广播 |
| 12 | 业务线程池;EventLoop.execute 任务队列;上下文传递 |
| 13 | 直接内存池;MappedByteBuffer 与 transferTo 静态文件 |
| 14 | 读写水位与背压;超时调度;SIGINT 连接排空 |
| 15 | linkd v1 验收清单;ab 压测脚本;故障复盘记录 |
linkd v1 的功能边界固定:HTTP 9090、健康检查 /healthz、只读 /books/{id} 代理到 libraryd 的 8080、WebSocket /ws/echo、明文 h2c 教学实现、SIGINT 优雅关闭。业务接口允许返回固定假响应,正文会标注;HTTP/2 不声称生产级。
三卷衔接
本书是《Java 网络编程基础》三卷本的第一卷。三卷共用 linkd,但每卷的技术栈和问题层次不同。
| 卷 | 技术栈 | 与本书的衔接 |
|---|---|---|
| 卷一(本书) | JDK 25 标准库 | 建立基线:ByteBuffer、Selector、Handler、手写协议 |
| 卷二 | Netty 4.2 | 用 ByteBuf、EventLoop、ChannelPipeline 重写第 6–11 章,逐项对照 |
| 卷三 | gRPC、协议设计、生产化 | 把第 8–10 章的协议边界升级为协议规范、版本兼容与服务治理 |
前置内容来自 Java 四卷本:卷三《Java 高级编程》的线程、JMM、虚拟线程,对应本书第 6、12 章;卷四《Java 虚拟机原理与性能调优》的 JFR、线程转储、直接内存诊断,对应本书第 13、15 章。本书不重复这些机制,只在用到时给出最小上下文和指向。
实验口径
书里的「本机输出」统一来自下面这套环境;换机器后绝对值会变,字段和方向通常不变。
export JAVA_HOME=~/.jdks/jdk-25.0.5+8/Contents/Home
export PATH="$JAVA_HOME/bin:$PATH"
java -version && javac -version
Apple M1 Pro,10 核,32 GB,macOS 26.3 (25D125)
Temurin 25.0.5+8,Maven 3.9.12
平台与工具约定:
- macOS 没有
ss,连接诊断用netstat -anv -p tcp与lsof -nP -iTCP:9090。 - macOS 没有 epoll,
Selector基于 kqueue;本书不写 epoll 的实测。 tcpdump需要sudo,回环用-i lo0;没有实际抓包就不写时间线。- 压测用
/usr/sbin/ab;wrk、hey未安装,不写它们的实测。 - 端口固定:
linkd9090,libraryd8080;抓包与压测都走 loopback。 - 构建:
cd linkd && mvn -q -DskipTests compile;测试:mvn -q test。
三条纪律:
- 一次只改一个变量。端口、缓冲区、线程数、连接数、超时任何一项变了,数字就不能直接比。
- 单次运行只说明「这次发生了什么」,不当作结论;性能数字至少重复三次并给分布。
- 没有命令和输出的数字不写;工具没装的只讲用法,不编输出。
与站内其他内容的关系
- 《Java 编程入门》
:语言基础与
libraryCLI。 - 《Java 编程实战》
:工程化与
libraryd服务。 - 《Java 高级编程》 :线程、JMM、虚拟线程、JUC;本书第 6、12 章直接承接。
- 《Java 虚拟机原理与性能调优》 :JFR、线程转储、直接内存诊断;本书第 13、15 章引用其工具口径。
- 《MMO 服务器开发》 :Go 主线 + Java 21 对照的游戏服务端网络;本书不写游戏协议与跨服。
- network 专题 :协议全景、运维、Linux 数据面与 HTTP/3;本书讲 Java 标准库实现,不重复协议百科。
- Spring Boot 三部曲 :框架层;本书讲框架之下的连接与协议。
- 书稿专题 :全部书稿的入口。
每节的结构与验证
每一节按同一个骨架写,跳读时也能快速定位:
- 承接的问题:从
linkd的代码、抓包或故障切入。 - 核心机制:两到四个小节,代码与命令配套。
- 在 linkd 里落地:给出模块位置和交互对象。
- 常见错误与边界:给报错原文或错误写法。
- 小结:四到六条。
验证分四层:javac --release 25 编译、java 运行、tcpdump/netstat/lsof 观察协议与连接、ab 与 JFR 看性能与资源。每层都给出可复制命令;没有实际执行的输出标为「示意输出」,不冒充实测。
怎么用这本书
- 按顺序:从 1.1 开始,每节结尾有小结,下一节紧接着上一节的代码基线。
- 按目标:用路径一,先选「写服务器」「懂协议」「做排障」中的一个目标,再按列表跳读。
- 按症状:用路径二,从当前故障对应的症状进入,先跑诊断命令,再回补机制。
- 按项目:用路径三,按阶段改
linkd,每阶段结束跑一次mvn -q -DskipTests compile。
全书代码都在 linkd/ 下,不依赖 snippets/,也不修改 libraryd 的业务代码。遇到类型名或端口不一致,先回到前言
的「版本或结果不一致时怎么排查」,再对照本页的「项目状态」确认代码基线。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。