网络面试的下半场落在传输层与网络层:TCP 为什么可靠、握手挥手为什么是这个次数、连接数到底受什么限制,再到 IPv6、NAT、ARP 的分工。本篇选十一道题做深,每题给出结论、原理与可延伸的加分点。

考察地图

  • TCP 与 UDP 基础:两者区别与选型、字节流与报文(粘包拆包)。考察对传输本质的理解。
  • 连接管理:三次握手为什么不是两次、四次挥手与 TIME_WAIT。考察连接状态机。
  • 可靠性与连接维护:可靠传输机制、双层 Keepalive 之分、65535 连接数迷思。
  • IP 与地址:客户端真实 IP 获取、IPv4 vs IPv6、NAT、ARP。
  • 建议自行查阅:基于 TCP/UDP 的协议清单、IP 地址过滤、MAC 地址细节、HTTP 各版本基于什么传输——HTTP/3 与 QUIC 在上篇已展开,这里不再重复。

TCP 与 UDP 基础

TCP 与 UDP 有什么区别?

结论:三条根差异——TCP 面向连接、可靠、字节流;UDP 无连接、尽力交付、保留报文边界。其余差异都是这三条的展开。

原理:展开成七个维度。连接:TCP 先握手后传输再挥手,UDP 直接发;可靠性:TCP 靠序号、确认、重传、流量与拥塞控制,UDP 什么都不保证;状态:TCP 两端维护窗口与序号,UDP 无状态所以开销小;传输形式:TCP 字节流不保留消息边界,UDP 一个报文一个包;首部:TCP 至少 20 字节,UDP 固定 8 字节;通信模式:TCP 仅单播,UDP 支持单播、多播、广播;效率:TCP 重、UDP 轻。

延伸:选型逻辑要脱口而出——要准确完整(网页、文件、邮件、SSH)选 TCP;要实时且能容忍少量丢失(音视频、游戏状态同步、DNS、DHCP)选 UDP。再补一句:QUIC 证明了「基于 UDP 也能做到可靠」,可靠性不取决于协议名字,而取决于有没有实现那套机制。

追问:在 UDP 上自己做可靠性需要哪些组件?提示:序号、ACK、超时重传、去重、滑动窗口——等于重写一个精简版 TCP。

为什么 TCP 是面向字节流,UDP 是面向报文?

结论:TCP 只保证字节可靠有序到达,不保证一次 send 对应一次 recv;UDP 一次交付就是一个数据报,天然保留消息边界。

原理:TCP 把应用写入的数据放进内核缓冲区,按 MSS 与窗口切割或合并后发送;接收方可能一次读到半条消息,也可能一次读到多条,这就是粘包与拆包。UDP 则相反,应用给多大的块就发多大的块,接收方按报文读,但不可靠、不保证顺序。

延伸:粘包的根因是应用层没有定义消息边界,解法三选一——定长、分隔符、长度头。工程主流是长度头,但要处理好字节序、最大长度限制、半包缓存与连接异常关闭四个细节,说出这四个细节就算答透了。

追问:长度头方案被恶意宣告超大长度怎么办?提示:先做上限校验再分配缓冲区,别让一个伪造长度打爆内存。

连接管理

为什么 TCP 是三次握手,两次不行?

结论:两次无法让双方都确认「自己能发也能收」,也挡不住网络里滞留的历史连接请求;三次是让双方都验证收发能力的最小次数。

原理:逐次看双方视角。第一次 SYN:服务端知道客户端能发、自己能收;第二次 SYN+ACK:客户端确认双方收发正常,但服务端还不知道客户端能否收到自己的回包;第三次 ACK 补齐服务端视角。若只有两次,一个滞留的旧 SYN 到达服务端就会直接建连,客户端却不认账,资源白白占用。

延伸:两个加分点——第三次握手起就可以携带应用数据;SYN 泛洪攻击正是利用半连接队列,防御手段是 syncookie 与调大 backlog,而不是盲目加内存。

追问:为什么第二次握手的 SYN 和 ACK 能合并,挥手的 ACK 和 FIN 却常分开发?提示:被动关闭方可能还有数据没发完,无法立刻 FIN。

为什么挥手要四次?TIME_WAIT 在等什么?

结论:TCP 全双工,两个方向要各自独立关闭,所以四步;主动关闭方的 TIME_WAIT 等 2MSL,一是让最后一个 ACK 丢失时对端的重传 FIN 还能被响应,二是让本连接的旧报文在网络中消亡,避免污染四元组相同的新连接。

原理:主动方发 FIN,被动方回 ACK 后进入半关闭;被动方把剩余数据发完再发 FIN,主动方回 ACK 后进入 TIME_WAIT。MSL 是报文最大存活时间,2MSL 恰好覆盖「ACK 丢失、对端重发 FIN」的一个往返。

延伸:TIME_WAIT 堆积多见于短连接高并发且本端主动关闭的场景,优化顺序是先查连接池与 keep-alive 有没有生效,再考虑 tcp_tw_reuse;别把它和 CLOSE_WAIT 混淆——CLOSE_WAIT 堆积意味着对端已关闭而本端应用忘了 close,是连接泄漏信号。

追问:大量 CLOSE_WAIT 指向什么 bug?提示:应用收到 FIN 后未调用 close,重点排查连接归还逻辑。

可靠性与连接维护

TCP 如何保证传输可靠性?

结论:一句话——序号加确认应答加超时重传打底,滑动窗口提效,流量控制护接收方,拥塞控制护网络,校验和防比特错误。

原理:每个字节都有序号,接收方按序累积确认;超时未收到 ACK 或收到三个冗余 ACK(快重传)就重发。接收窗口 rwnd 防止发送方打爆接收缓冲区;拥塞窗口 cwnd 经慢开始、拥塞避免、快重传、快恢复动态探测网络容量,实际发送窗口取两者的较小值。

延伸:分清流量控制与拥塞控制是高频追问——前者是点对点的端到端问题,后者是全局的网络负载问题。再补一个 SACK 选择性确认:只重传真正缺失的段,减少无效重发。

追问:重传超时时间怎么定?提示:基于加权平滑 RTT 动态计算,Karn 算法回避重传样本的二义性。

TCP Keepalive 和 HTTP Keep-Alive 有什么区别?

结论:同名不同层。HTTP Keep-Alive 是应用层机制,复用连接以省掉反复建连的开销;TCP Keepalive 是传输层机制,探测长时间空闲的死连接以释放资源。

原理:HTTP/1.1 默认长连接,由 timeout 与 max 控制,服务端到期「主动回收」,不需要问客户端死活。TCP Keepalive 默认关闭,开启后空闲超过阈值才发探测包,多次无响应才判定对端死亡——是「被动回收」,对端能回 ACK 就得一直维持。

延伸:两者都替代不了业务心跳:TCP 能回 ACK 不代表应用线程没卡死;连接经过 NAT 或负载均衡时,探测到的可能只是中间某一段。Web 实战里三层心跳各管各的,答出这句就显出深度。

追问:长连接经过 NAT 为什么会被悄悄掐断?提示:NAT 映射表的空闲超时远小于 TCP 理论存活时间,映射一清,报文有去无回。

一台主机最多只能保持 65535 个 TCP 连接吗?

结论:不是。65535 是端口号上限,不是连接数上限。连接靠四元组(源 IP、源端口、目的 IP、目的端口)区分,只要四元组不同就是不同连接。

原理:服务端监听同一个端口,客户端的 IP 与端口组合近乎无限,真正的瓶颈在文件描述符、内存、CPU 与应用处理能力。端口瓶颈出现在客户端:连同一个目标时源 IP 与目的地址都固定,只剩源端口可变,Linux 默认临时端口约 2.8 万个,叠加 TIME_WAIT 占用就容易撞墙;NAT 网关侧同理。

延伸:顺带可答「TCP 和 UDP 能用同一个端口吗」——能,内核按 IP 协议号(TCP 是 6、UDP 是 17)先分流再按端口分发,DNS 同时用 UDP/53 和 TCP/53 就是活例。生产环境最常见的坑其实不是端口耗尽,而是连接池没配好导致短连接疯狂建拆。

追问:客户端撞临时端口上限怎么破?提示:连接池复用、调大 ip_local_port_range、多源 IP 出站。

IP 与地址

如何获取客户端真实 IP?

结论:应用层靠 X-Forwarded-For 或标准 Forwarded 头,传输层靠 TCP Options 或 Proxy Protocol,网络层靠隧道加 DSR。无论哪种,前提是只信任你自己部署的代理写入的部分。

原理:每过一层反向代理,XFF 就在尾部追加一跳地址,但它是明文头、客户端可随意伪造——可信网关必须覆盖或规范化外部传入值,业务代码只从已知代理位置取值。Proxy Protocol 在 TCP 连接开头携带真实四元组,Nginx、HAProxy 都支持,与上层应用协议无关,更干净。

延伸:两个实战误区——多层代理下直接取 remote_addr 只能拿到上一跳;不做信任链边界的 IP 限流会被伪造 XFF 轻松绕过,风控系统必须明确「从右往左数第几跳可信」。

追问:CDN、WAF、LB、Nginx、应用五级链路怎么取真实 IP?提示:固定可信跳数并让网关注入专用头,别让跳数配置漂移。

IPv4 和 IPv6 有什么区别?

结论:最核心的差异是地址空间——32 位约 42 亿个对 128 位;其余改进都是「地址够用之后」的顺势设计。

原理:IPv6 的主要变化:SLAAC 无状态自动配置,主机根据路由器通告的前缀自行生成地址,不必依赖 DHCP;地址充足使 NAT 从必需品降级为可选项;基本头部定长简化、选项拆成独立扩展头,常见转发路径更规整;ICMPv6 整合了邻居发现与路径 MTU 发现。表示法从点分十进制变为冒号十六进制加零压缩。

延伸:现实是双栈长期共存,过渡靠隧道与 NAT64。答题别踩两个坑——不能说「IPv6 更快」,性能取决于实现与策略;也不能说「IPv6 天然更安全」,IPsec 只是可选能力而非强制。

追问:地址都够用了,NAT 为什么还没消失?提示:隐藏拓扑的安全语义、存量 IPv4 资产、运营商成本惯性。

NAT 的作用是什么?

结论:把内网私有地址映射为公网地址——通常连端口一起改写(即 NAPT),让多台内网主机共享一个公网 IP 访问互联网。

原理:出向报文经过 NAT 网关时被改写源 IP 与源端口,网关记录映射表;回包查表还原后转交内网主机。它缓解了 IPv4 地址枯竭,附带「隐藏内网拓扑」的效果——但要讲清楚:决定入站报文能否进来的是过滤策略,不是地址转换本身,NAT 不能替代防火墙。

延伸:NAT 破坏了端到端原则,两个连锁反应值得答:P2P 与 WebRTC 要靠 STUN/TURN 打洞或中继;长连接经过 NAT 会因映射空闲超时被悄悄清理,这是应用层必须实现业务心跳的深层原因。

追问:对称 NAT 为什么最难打洞?提示:它给每个不同目标分配不同映射端口,外部无法根据已知映射预测新映射。

ARP 解决了什么问题?

结论:解决「知道下一跳 IP、但链路层发帧需要 MAC」的映射问题。IP 是逻辑地址,MAC 才是本地链路上真正投递帧用的地址。

原理:发送方先查本机 ARP 缓存,未命中则广播 ARP 请求「谁的 IP 是 192.168.1.1」,目标主机单播应答,双方把映射写入缓存供后续复用。注意两点边界:ARP 广播不出本网段,只在同一广播域内工作;跨网段通信时,解析的其实是默认网关的 MAC,之后逐跳重新封装。

延伸:两个加分点——免费 ARP(主机主动广播自己的 IP-MAC)用于 IP 冲突检测与高可用主备切换时的缓存刷新;ARP 协议没有认证机制,ARP 欺骗可以把流量引向攻击者,是局域网中间人攻击的第一步。

追问:IPv6 里 ARP 去哪了?提示:被 ICMPv6 邻居发现协议(NS/NA 报文)取代,功能更强且基于组播。