Wireshark抓Java TCP流量需结合tcpdump,确认监听地址、容器网络、IPv4/6设置;重传用tcp.analysis.retransmission过滤;零窗口需查GC和接收缓冲区;加密流量需密钥解密,close不等于FIN立即发送。

Wireshark 怎么抓到 Java 进程的真实 TCP 流量
Java 应用走的是标准 socket,Wireshark 本身不区分语言,但容易漏抓——因为流量可能没走你预期的网卡,或被容器/代理劫持。tcpdump 配合 Wireshark 才可靠。
- 先用
netstat -tulnp | grep java或lsof -i -P -n -sTCP:LISTEN | grep java确认 Java 进程监听的ip:port和绑定地址(0.0.0.0vs127.0.0.1) - 若应用跑在 Docker 里,别在宿主机抓
lo,得进容器抓,或用docker run --net=container:<id> -it --cap-add=NET_ADMIN nicolaka/netshoot tcpdump -i eth0 -w /tmp/out.pcap - Java 启用了
-Djava.net.preferIPv4Stack=true?如果没设,可能混发 IPv6 流量,Wireshark 默认显示所有协议,记得加过滤器ip.version == 4 && tcp
怎么快速定位 TCP 重传(Retransmission)
重传不是“有就一定有问题”,关键看频次和上下文。Wireshark 不会直接标“这是重传”,得靠序列号和时间戳交叉判断。
- 开启
TCP sequence number analysis:菜单 Analysis → Enabled Protocols → TCP → Enable “Allow subdissector to reassemble TCP streams”,否则[TCP Retransmission]标签不会高亮 - 过滤重传包最准的表达式是:
tcp.analysis.retransmission(注意不是tcp.flags.retransmission,后者不存在) - 单次重传可能是丢包,连续 3 次以上重传 +
tcp.analysis.lost_segment出现,大概率是链路或接收端问题;如果重传后立刻收到ACK,但后续又重传,要怀疑发送端缓冲区或 Nagle 算法干扰 - Java 侧常见诱因:
Socket.setSoTimeout()设得太小、BufferedOutputStream未 flush、Netty 的ChannelConfig.setWriteSpinCount()过低导致写失败被静默重试
零窗口(Zero Window)怎么看、怎么确认是不是 Java 自身导致
零窗口表示接收方 TCP 缓冲区已满,通告窗口为 0。它本身是流控机制,但持续出现说明 Java 应用读太慢,或 GC 卡顿阻塞了网络读线程。
- Wireshark 中找
tcp.window_size == 0,再结合tcp.analysis.window_update看后续有没有恢复窗口的报文;如果长期卡在 0,且tcp.len == 0(纯 ACK 包),就是接收方“堵死”了 - 重点查 Java 进程的堆内存和 GC 日志:
Full GC期间可能长达几百毫秒不处理 socket 读事件,Netty 的EpollEventLoop或 NIO 的Selector.select()会被挂起 - 检查是否禁用了
SO_RCVBUF自动调优:socket.setReceiveBufferSize(0)会导致系统用最小默认值(如 256KB),小缓冲区更容易触发零窗口;建议显式设为1MB以上并配合 OS 参数net.core.rmem_max - Spring Boot WebFlux 用户注意:
flatMap并发数没限流 + 背压没处理好,也会让下游消费线程来不及读,最终反馈为零窗口
Java 抓包时容易忽略的两个底层事实
Wireshark 显示的是内核协议栈收发的数据包,而 Java 看到的是应用层字节流——中间隔着 socket 缓冲区、TLS 加密、JVM 网络栈实现细节。很多“对不上”的现象根源在这里。
立即学习“Java免费学习笔记(深入)”;
-
SSLSocket或HttpsURLConnection的流量在 Wireshark 里是加密的,看不到 HTTP 明文,除非配置 JVM 系统属性javax.net.debug=ssl:handshake或用 NSS Key Log File(需 Java 8u251+)导出密钥 - Java 的
Socket.close()不等于 FIN 发送完成;它只是把 socket 标为关闭,内核可能延迟发送 FIN,Wireshark 里看到 FIN 延迟 100ms+ 很正常,别误判为连接泄漏 - Netty 的
PooledByteBufAllocator如果内存池耗尽,write 操作会 fallback 到 unpooled 内存,导致额外 GC 和 write 耗时毛刺——这种问题 Wireshark 只能看到“写间隔变长”,得结合io.netty.util.internal.PlatformDependent.hasUnsafe()和 GC 日志交叉分析










