《Java 网络编程基础》附录 B 网络诊断命令清单
《Java 网络编程基础》附录 B:macOS 26.3 上可直接复制的网络诊断命令,覆盖 netstat -anv -p tcp、lsof -nP -iTCP:9090、sudo tcpdump -i lo0、nc、curl -v、ab、jcmd Thread.print 与 VM.native_memory,每条给用途、关键列读法与常见误判。
tag
《Java 网络编程基础》附录 B:macOS 26.3 上可直接复制的网络诊断命令,覆盖 netstat -anv -p tcp、lsof -nP -iTCP:9090、sudo tcpdump -i lo0、nc、curl -v、ab、jcmd Thread.print 与 VM.native_memory,每条给用途、关键列读法与常见误判。
《Java 网络编程基础》附录 A:把 InetAddress、Socket、ServerSocket、SocketChannel、ServerSocketChannel、Selector、ByteBuffer、FileChannel 八组 API 压成速查表,逐条给签名、作用、易错点与最小示例,按 JDK 25 核对,并附 linkd 类映射与异常对照表。
v1 能跑通不等于能交付。本节把前 14 章收成一张 linkd v1 验收清单:健康检查、keep-alive、HTTP/2 preface、WebSocket 升级、TLS、优雅关闭逐条给命令与判据,再用 AcceptanceChecklist 自动跑可自动化的部分,最后给出故障注入项与复盘模板,形成可复现的发布记录。
ab 能跑出数字,但吞吐、p50/p95/p99、错误数和连接数必须一起读,单看 QPS 会得出相反结论。本节确认本机 ab 可用、wrk 不在,用三次 keep-alive 与一次非 keep-alive 实测 /healthz,给出 LoadTestPlan 的 Little 定律并发估算、分位算法与验收判定。
连接卡住时线程栈只说它在等,netstat 才说等到哪一步。本节用 macOS 的 netstat -anv -p tcp、lsof -nP -iTCP 实测 CLOSE_WAIT、TIME_WAIT、SYN_SENT 三种状态,讲 sudo tcpdump -i lo0 的读法与权限边界,把 linkd 的 ConnectionDiagnostics 接进排查链并给出误判边界。
停掉 accept 不等于优雅关闭:写队列没排空就退出,客户端会看到响应被截断。本节用 linkd 的 GracefulShutdown 接住 SIGINT,停止接收新连接、按连接半关闭、在期限内排空,超时后强制关闭,并给出可复现的阶段输出。
连接超时、读超时和请求期限常被混成一个数字,重试又会把一次失败放大成多倍流量。本节用 linkd 的 RetryPolicy 区分失败阶段、计算带抖动的退避、约束总期限,并在 libraryd 上游调用中给出幂等键复用与只对安全操作重试的判断表。
写队列只设一个阈值,暂停与恢复会在事件循环里反复抖动。本节用 linkd 的 WatermarkHandler 实现高低水位滞回、写队列硬上限、暂停与恢复 OP_READ、令牌桶读限速和帧边界丢弃,并给出可复现的水位迁移、令牌桶配额与硬上限关闭输出。
MappedByteBuffer 的映射、刷盘与取消映射各有边界。本节用 MapProbe 验证只读 force 为空操作、通道关闭不解除映射与 Arena 关闭后的 IllegalStateException,再用 MappedFileServer 对比 mmap 与 transferTo,给出静态文件发送的选择依据与 linkd 落地方式。
DirectByteBuffer 的分配与回收不在一条时间线上。本节拆开 Cleaner、MaxDirectMemorySize 与 NMT 三本账,用 DirectMemoryBudget 复现预算拒绝、切片共享、可达泄漏与不可达回收,并给出 linkd 中 BufferPool 的所有权规则与泄漏判定顺序。
零拷贝不是一个系统调用的别名。本节用 8 MiB 文件在 loopback 上拆开 JDK 25 的 transferTo 三级分派,解释返回值 0 的三种来源,并用包裹通道与 JFR 证明:一次返回 8 MiB 也可能只是 1024 次 8 KB 拷贝,macOS 上不要照搬 Linux sendfile/epoll 的结论。
本节处理跨线程的请求上下文:ThreadLocal 在线程池中的残留与泄漏、ScopedValue 在 JDK 25 的绑定与恢复、事件循环到业务线程的显式传播,以及不可变消息与 happens-before 如何建立可见性;给出可运行的 RequestContext 与本机输出。
本节给 linkd 补业务线程池:用有界队列和命名线程隔离阻塞任务,按 CPU 与等待比估算线程数,解释 CallerRunsPolicy 为何会把阻塞带回事件循环,并给出指标与拒绝路径;最后用 JDK 25 虚拟线程做同负载对照,附可复现命令与本机单次数据。
本节拆开 linkd 事件循环的调度层:任务队列为什么必须是多生产者单消费者、execute 的线程归属与重入边界、selector.wakeup 的合并条件、定时任务的最小堆与 select 超时算法,以及一次 500 毫秒阻塞如何让心跳延迟到任务结束;给出可运行的 EventLoopImpl 与本机输出。
在帧编解码之上补齐连接生命周期:用 ping/pong 检测半开连接,按 1000、1001、1002 等关闭码完成关闭握手,并用 ConcurrentHashMap 会话表与每会话有界发送队列实现线程安全广播,给出 WebSocketSessionImpl 与 WebSocketHub。
从 101 之后的第一段字节开始,拆开 WebSocket 的两字节帧头:FIN、RSV、opcode、MASK 与 7/16/64 位长度编码,讲清客户端掩码的 XOR 算法和控制帧的 125 字节上限,并用 WebSocketFrameCodec 处理半帧、continuation 分片与 UTF-8 校验。
从 linkd-ws 的 /ws/echo 升级请求出发,逐条校验 Upgrade、Connection、Sec-WebSocket-Version 与 Sec-WebSocket-Key,手写 SHA-1 加 GUID 再 Base64 的 Accept 计算,讲清 101 响应写完后协议切换点在哪里,并给出 WebSocketHandshake 的完整实现。
完整握手之后,linkd 还要决定复用哪条会话、用 h2 还是 http/1.1、以及证书到底属于谁。本节讲 TLS 1.3 session ticket 的复用口径、ALPN 协商与主机名校验,给出 TlsSessionPolicy,并用 PKIXParameters 校验证书链。
阻塞式 SSLSocket 会把握手绑在一条线程上,linkd 的 EventLoop 不能这样等。本节把 SSLEngine 封装成 NonBlockingTlsHandshake:逐轮驱动 wrap/unwrap,处理 BUFFER_OVERFLOW、BUFFER_UNDERFLOW 与 NEED_TASK,最后用 TlsHandshakeHandler 接进 6.2 的事件循环。
从 linkd 明文代理必须加密的约束出发,拆解 TLS 1.3 的 1-RTT 握手、ClientHello/ServerHello 与证书链;用 keytool 生成带 SAN 的 PKCS12 自签证书,再用 TlsHandshakeInspector 打印协议、套件、证书链与 SAN,并给出证书不匹配的排查顺序。