🎤 高频真题
TIME_WAIT/CLOSE_WAIT 堆积 · TCP 粘包 · HTTPS 中间人 · 连接池连接数
1. 线上大量 TIME_WAIT 怎么办?
来源:主动关闭连接的一方进入 TIME_WAIT。常见于服务端主动关闭 + 短连接高并发(如连接池满时服务端 close、代理转发场景)。
排查:netstat -ant | grep TIME_WAIT | wc -l;ss -s 看汇总。
解决(按推荐顺序):
- 根本:长连接复用(HTTP keep-alive/连接池),减少建连-断连频率
- 调整内核参数(谨慎,有副作用):
- net.ipv4.tcp_tw_reuse = 1(仅对客户端出站连接有效,复用 TIME_WAIT 连接)
- net.ipv4.tcp_timestamps 开启(tw_reuse 依赖)
- tcp_max_tw_buckets:超出则销毁新 TIME_WAIT(缓解,不是根治)
- 应用侧:服务端尽量不主动 close(让客户端关)
CLOSE_WAIT 堆积:则是代码 bug——收到 FIN 后应用没调 close(连接未释放),排查:jstack 看哪个线程持有未关闭的连接/IO 流。
🎯 面试要点
- TIME_WAIT 多 = 连接频繁关闭(架构问题);CLOSE_WAIT 多 = 代码没关(bug)——先区分再答
- 调整内核参数要讲清副作用(tw_reuse 影响 NAT 场景等),显示工程素养
2. 什么是 TCP 粘包/拆包?怎么解决?
原因:TCP 是字节流协议,没有消息边界。多个消息可能被合并发送(粘包),一个消息也可能被拆成多次发送(拆包)。应用层需要自己定义边界。
解决(三种主流):
- 固定长度:每个消息定长,不足补位。简单但浪费
- 分隔符:消息末尾加特殊字符(\n、\r\n)。注意内容中不能出现分隔符
- 长度前缀(最常用):消息头 4 字节记录长度 + 消息体。Netty 的 LengthFieldBasedFrameDecoder 就是干这个的
自定义协议:长度前缀
// 协议:| 4字节总长度 | 消息体 |
// 发送方:
ByteBuf buf = new ByteBuf(...);
buf.writeInt(msg.length); // 长度头
buf.writeBytes(msg.getBytes());
// 接收方:
// 先读 4 字节长度 → 读满 length 字节才算一个完整消息
// Netty:pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4))
🎯 面试要点
- 粘包/拆包是 TCP 的特性不是 bug;UDP 有消息边界所以没有这问题
- RPC 框架(Dubbo 协议)都自带长度头——面试可举例
3. HTTPS 能防中间人攻击吗?证书的作用?
- 能防标准中间人:中间人无法伪造证书(没有私钥+没有 CA 信任)
- 证书的作用:把"公钥"与"域名/主体"绑定,由 CA 签名背书——解决"如何安全拿到对方公钥"(公钥分发难题)
- 中间人如何仍可能成功:用户信任了伪造的根证书(企业内网代理、钓鱼安装)、证书域名不匹配但用户点了"继续"、受信任的 CA 被攻破(极少)
- 验证点:证书链完整、域名匹配(CN/SAN)、未过期、未吊销(OCSP)
🎯 面试要点
- HTTP 明文抓包随便看;HTTPS 抓包要用中间人证书(如 Charles 需安装它的 CA)——原理就是这个
- 证书有效期/续期:免费 Let's Encrypt(90 天自动续)
4. 一台服务器最多能建立多少 TCP 连接?
- 客户端限制:四元组(源 IP:源端口, 目标 IP:目标端口),Linux 默认临时端口范围
net.ipv4.ip_local_port_range = 32768 60999→ 单 IP 对单目标约 2.8 万(6.5 万是 16 bit 端口号的理论上限);多客户端 IP 则无限放大(NAT/多网卡) - 服务端限制:理论上远大于此(fd 数、内存决定)——每个连接占内核内存(socket 缓冲 + TCP 控制块,约几 KB)
- 实际瓶颈:
ulimit -n(文件描述符上限,默认 1024!生产要调大)、内存、CPU
🎯 面试要点
- 连接数不是性能指标:活跃连接才是;C10K → C10M 问题是网络面试经典话题
- nginx 高并发配置:worker_connections、ulimit 调大、epoll
- 调优命令:ulimit -n 65535;sysctl 看 tcp 内存 net.ipv4.tcp_mem