计算机网络八股文:TCP 与 UDP 两万字详解

发布时间:2026/9/18 21:53:05

计算机网络八股文:TCP 与 UDP 两万字详解 一、计算机网络体系结构基础在正式进入 TCP 和 UDP 之前有必要先理解计算机网络为什么要分层、每一层分别负责什么。因为只有搞清楚「TCP 和 UDP 位于哪一层、它们的下层依赖什么、上层又为谁服务」才能真正理解这两个传输层协议的定位、设计动机以及它们的很多行为为什么会是现在这个样子。1.1 为什么要分层计算机网络是一个极其复杂的系统涉及物理介质、信号编码、数据帧收发、路由选择、端到端传输、应用解析等环节。如果把这些逻辑全部揉在一起任何一点修改都会牵一发动全身。因此学术界和工业界采用了「分层」的思想把整个通信过程拆成若干层每一层只负责一件相对独立的事情。分层带来的好处主要有四点各层独立每一层只需要完成自己的功能不需要关心其他层的内部实现。例如 IP 协议不关心数据是 TCP 还是 UDP 承载的也不关心应用层是 HTTP 还是 DNS。灵活性好某一层的实现可以被替换只要它与相邻层的接口不变。例如物理层从网线换成光纤上层完全不需要感知。结构清晰每一层的职责明确便于学习和排错。排查网络问题时可以逐层定位比如先看物理链路是否通再看 IP 是否可达最后看端口和应用是否正常。促进标准化不同厂商只要遵循同一层的接口规范就可以实现互联互通。分层也有一定代价比如会增加额外的封装开销、可能出现功能重复等但整体而言分层带来的收益远大于成本。1.2 OSI 七层模型OSI即开放系统互连参考模型是国际标准化组织提出的理论模型共分七层。它更多地用于教学和理论分析现实中的协议栈并没有严格照搬 OSI。层级名称主要功能典型协议/设备7应用层为应用程序提供网络服务HTTP、DNS、FTP、SMTP6表示层数据格式转换、加密、压缩JPEG、SSL/TLS 的部分功能5会话层建立、管理、终止会话RPC、NetBIOS4传输层端到端可靠或不可靠传输TCP、UDP3网络层逻辑寻址、路由选择IP、ICMP、路由器2数据链路层物理寻址、成帧、差错检测以太网、交换机1物理层比特流传输、物理接口网线、光纤、集线器其中传输层是本文的核心。它负责「端到端」的通信也就是两个主机上的进程之间的通信。网络层虽然能把数据从源主机送到目的主机但它只能保证主机到主机至于数据最终交给目的主机上的哪个进程就需要传输层通过端口号来完成区分。1.3 TCP/IP 四层模型TCP/IP 模型是实际互联网使用的协议体系它将 OSI 的七层合并为四层应用层对应 OSI 的应用层、表示层、会话层协议有 HTTP、HTTPS、DNS、FTP、SMTP、SSH 等。传输层对应 OSI 的传输层核心协议就是 TCP 和 UDP。网络层也称网际层对应 OSI 的网络层核心协议是 IP还有 ICMP、ARP 等辅助协议。网络接口层对应 OSI 的数据链路层和物理层负责把数据真正通过物理介质发出去。在实际学习时很多人更习惯使用「五层模型」应用层、传输层、网络层、数据链路层、物理层。它结合了 OSI 的清晰和 TCP/IP 的实用本系列后续内容都基于五层模型展开。1.4 数据封装与解封装数据的传输过程可以概括为「层层封装、对端层层解封」。以一次 HTTP 请求为例应用层生成 HTTP 报文交给传输层。传输层根据协议选择 TCP 或 UDP。如果使用 TCP会在应用层数据前加上 TCP 首部形成 TCP 报文段。网络层在 TCP 报文段前加上 IP 首部形成 IP 数据报。数据链路层加上帧头和帧尾形成数据帧最终通过物理层以比特流的形式发送出去。接收端则反过来物理层收到比特流后数据链路层根据帧尾校验解出 IP 数据报网络层解出 TCP 报文段传输层根据目的端口号把数据交给对应的应用进程。理解了分层模型之后下面正式进入 UDP 和 TCP。这两个协议都工作在传输层但它们的哲学几乎完全相反UDP 追求「简单、快速、无连接」TCP 追求「可靠、有序、面向连接」。这两者的差异正是面试中最核心、最常考的内容。二、UDP 协议详解2.1 UDP 是什么UDP全称 User Datagram Protocol即用户数据报协议。它是一种无连接的传输层协议提供的是「尽最大努力交付」的不可靠传输服务。所谓「无连接」指的是发送数据之前不需要像 TCP 那样先通过握手建立连接。发送方只要知道目的 IP 和目的端口就可以直接把数据报发出去不需要等待对方应答也不需要维护连接状态。所谓「不可靠」指的是 UDP 不保证数据一定能到达目的地不保证到达顺序也不保证数据不重复。如果报文在传输过程中丢失、乱序或者损坏UDP 本身不做任何处理这些问题需要由应用层自己负责。可以把 UDP 类比为寄明信片你把明信片写上地址投进邮筒能不能寄到、会不会损坏、会不会比后寄的到得晚你都无法控制也不会有回执。这是一种非常直接的通信方式。2.2 UDP 报文格式UDP 报文由首部和数据两部分组成。UDP 首部极其简单只有固定的 8 个字节共 4 个字段每个字段 2 字节字段长度说明源端口号16 位发送方进程使用的端口号。该字段可选如果不需要回复可以填 0目的端口号16 位接收方进程使用的端口号用于把数据交给正确的应用长度16 位UDP 首部和数据的总字节数最小值为 8校验和16 位用于检测 UDP 报文在传输中是否出错可选字段首部结构大致可以表示如下0 7 8 15 16 23 24 31 -------------------------------- | 源端口号 | 目的端口号 | -------------------------------- | 长度 | 校验和 | -------------------------------- | 数据部分 | ------------------------------------可以看到UDP 首部没有序号、确认号、窗口大小、标志位等字段。这正是它简单高效的原因首部开销小只有 8 字节而 TCP 首部最小也有 20 字节。关于校验和需要注意两点第一UDP 的校验和覆盖范围包括「伪首部 UDP 首部 数据」。伪首部取自 IP 首部的部分信息包含源 IP、目的 IP、协议号和 UDP 长度。引入伪首部是为了让 UDP 也能检查 IP 地址是否在传输中出错因为单纯检查 UDP 报文本身无法发现「目的 IP 被改」这类问题。第二UDP 校验和是可选的在 IPv4 中可以填 0 表示不计算校验和但在 IPv6 中校验和是强制的。2.3 UDP 的主要特点特点一无连接UDP 发送数据前不需要建立连接因此也就没有连接建立和释放带来的时延。对于一次性的、小规模的请求比如 DNS 查询UDP 可以显著降低延迟。特点二首部开销小UDP 首部只有 8 字节TCP 首部最小 20 字节。对于小报文场景TCP 的首部占比会非常高而 UDP 则能把更多带宽留给真正有用的数据。特点三不保证可靠交付UDP 不保证数据包一定能到达、不乱序、不重复。由于没有确认和重传机制UDP 无法告诉发送方数据是否成功送达。可靠性必须由应用层自己实现比如 QUIC 协议就是在 UDP 之上实现了类似 TCP 的可靠传输。特点四面向报文UDP 是面向报文的。应用层交给 UDP 多长的报文UDP 原样发送既不拆分也不合并。一次 sendto 发送一个 UDP 数据报对端一次 recvfrom 接收一个 UDP 数据报。如果应用层发送的报文太长超过了 IP 层的最大传输限制IP 层会负责分片如果报文太短UDP 也不会把多个报文合并。相应地应用层需要自己处理报文边界问题。特点五支持广播、组播和一对多通信这是 UDP 一个非常重要的优势。TCP 是点对点的只能在一对连接之间通信无法广播。而 UDP 天然支持向多个地址发送数据包括单播、广播和多播。视频直播、局域网设备发现等场景非常依赖这一特性。特点六没有拥塞控制UDP 发送数据的速率由应用层自行决定网络拥塞时 UDP 也不会主动降低发送速率。这既是优点也是缺点优点是实时性高、时延可控缺点是可能加剧网络拥塞挤占其他流量。很多实时应用宁可偶尔丢包也不愿意等待重传因此选择 UDP 并接受这一风险。2.4 UDP 的典型应用场景DNS 域名解析DNS 查询通常只有一个请求和一个响应数据量小、时延敏感。使用 UDP 可以避免三次握手开销。不过当响应超过 512 字节时DNS 会改用 TCP。DHCP 动态地址分配主机刚开机时还没有 IP 地址无法建立常规连接DHCP 使用 UDP 广播来发现服务器并获取 IP 配置。实时音视频通话视频会议、语音通话、直播等场景对实时性要求极高少量丢包可以通过编解码和插值弥补但延迟过大和频繁重传会严重影响体验因此普遍使用 UDP。在线游戏很多游戏要求玩家操作的同步延迟尽可能低偶尔丢失一两个位置包不会造成严重影响因此常用 UDP。物联网和局域网发现协议如 mDNS、SSDP 等设备发现协议依赖广播和多播只能使用 UDP。QUIC 协议HTTP/3 底层使用 QUIC而 QUIC 基于 UDP 实现。这代表了「在 UDP 之上自行实现可靠传输和拥塞控制」的新趋势。2.5 关于 UDP 的常见误区误区一UDP 一定比 TCP 快。UDP 首部小、无需握手在同等条件下通常延迟更低但如果应用层在 UDP 之上实现了复杂的可靠传输机制总体性能未必优于经过高度优化的 TCP 实现。要具体场景具体分析。误区二UDP 完全没有任何差错检测。UDP 有校验和字段可以检测报文在传输中的比特错误只是它不负责纠错和重传。误区三UDP 不能可靠传输。UDP 本身不可靠但可以在其之上构建可靠传输QUIC 就是典型案例。协议本身和应用层实现要分开看。三、TCP 协议详解3.1 TCP 是什么TCP全称 Transmission Control Protocol即传输控制协议。它是一种面向连接的、可靠的、基于字节流的传输层协议。与 UDP 形成鲜明对比TCP 在设计上追求的是数据必须完整无误地到达且顺序正确。为了实现这一目标TCP 引入了连接管理、序号与确认、校验和、超时重传、滑动窗口、流量控制、拥塞控制等一系列机制。可以说TCP 的复杂性绝大部分都来源于「可靠」二字。TCP 可以被类比为打电话拨号接通、确认对方身份、按顺序交流、挂断前明确告别。整个过程中双方都在不断地确认信息是否被正确接收。3.2 TCP 报文段格式TCP 报文段同样由首部和数据组成。TCP 首部最小 20 字节最大 60 字节。主要字段如下字段长度说明源端口号16 位发送方进程端口目的端口号16 位接收方进程端口序号32 位本报文段数据第一个字节的序号用于保证顺序和去重确认号32 位期望收到对方下一个报文段的序号表示该序号之前的数据都已收到数据偏移4 位指示 TCP 首部长度单位是 4 字节因此首部长度必须是 4 字节的整数倍保留位6 位保留给未来使用目前填 0控制位6 位包括 URG、ACK、PSH、RST、SYN、FIN用于连接管理和状态控制窗口大小16 位接收方当前可用的接收缓冲区大小用于流量控制校验和16 位覆盖伪首部、TCP 首部和数据用于差错检测紧急指针16 位仅当 URG 标志为 1 时有效指示紧急数据的偏移选项可变如最大报文段长度 MSS、窗口扩大、时间戳、选择性确认 SACK 等六个控制位的含义如下URG紧急指针有效。表示报文段中有需要优先处理的紧急数据。ACK确认号有效。连接建立后除最初 SYN 报文外几乎所有报文都会携带该标志。PSH提示接收方尽快把数据交给应用层不要长时间停留在缓冲区。RST重置连接。用于异常情况下强制断开连接例如收到一个不属于任何已建立连接的报文。SYN同步序号。仅用于建立连接时协商初始序号。FIN结束标志。用于正常关闭连接表示发送方已经没有数据要发送了。TCP 首部结构示意如下0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -------------------------------- | 源端口号 | 目的端口号 | -------------------------------- | 序号 | -------------------------------- | 确认号 | -------------------------------- | 数据偏移 | 保留 |U|A|P|R|S|F| 窗口大小 | -------------------------------- | 校验和 | 紧急指针 | -------------------------------- | 选项长度可变 | -------------------------------- | 数据部分 | --------------------------------3.3 TCP 三次握手三次握手是 TCP 面试中几乎必问的内容不仅要能说出「SYN、SYNACK、ACK」这三个报文还要理解为什么必须是三次以及其中涉及的初始序号、状态变化和异常场景。3.3.1 三次握手过程假设客户端主动发起连接服务器被动监听。完整过程如下第一次握手客户端向服务器发送一个 SYN 报文段。该报文段中 SYN 标志置 1并携带客户端随机生成的初始序号 seq x。此时客户端进入 SYN_SENT 状态。这个报文不携带应用数据但会消耗一个序号。第二次握手服务器收到 SYN 后如果同意建立连接就回复一个 SYN ACK 报文段。该报文段中 SYN 和 ACK 标志都置 1确认号 ack x 1同时服务器也生成自己的初始序号 seq y。此时服务器进入 SYN_RCVD 状态。第三次握手客户端收到 SYN ACK 后再回复一个 ACK 报文段。该报文段中 ACK 标志置 1确认号 ack y 1序号为 seq x 1。发送后客户端进入 ESTABLISHED 状态。服务器收到这个 ACK 后也进入 ESTABLISHED 状态。至此双向连接建立完成双方可以开始传输数据。用一张表总结三次握手的状态和报文阶段发送方报文类型关键字段发送后状态第一次握手客户端SYNSYN1, seqxSYN_SENT第二次握手服务器SYNACKSYN1, ACK1, seqy, ackx1SYN_RCVD第三次握手客户端ACKACK1, seqx1, acky1ESTABLISHED三次握手完成后双方都确认了两件事第一自己的发送能力正常对方的接收能力正常第二对方的发送能力正常自己的接收能力正常。最终双方都确认了「发送和接收通道都是通的」。3.3.2 为什么是三次握手而不是两次这是面试中的经典追问。核心原因在于三次握手能够防止「已失效的连接请求报文段」突然又传到服务器从而避免服务器建立无意义的连接。考虑只有两次握手的情况。假设客户端发出第一个 SYN 报文但由于网络拥塞它长时间滞留在网络中没有及时到达服务器。客户端等待超时后认为连接建立失败于是重新发送 SYN并与服务器成功建立了连接完成数据传输后关闭连接。此时那个滞留在网络中的旧 SYN 报文终于到达了服务器服务器不知道这是已失效的请求于是回复 SYN ACK 并进入已连接状态等待客户端发送数据。而客户端此时已经不需要这个连接了不会理会服务器的响应。结果就是服务器白白维护着一个永远不会被使用的连接浪费资源。而三次握手可以避免这个问题客户端在收到服务器的 SYN ACK 后会再发送一个 ACK 进行最终确认。服务器只有在收到这个 ACK 后才建立连接。对于那个失效的旧 SYN客户端不会回复 ACK服务器也就不会建立连接。此外三次握手也能完成「双方初始序号的交换」。TCP 通信需要双方各自维护一个序号空间用于保证数据的顺序和去重。第一次握手由客户端告知服务器自己的初始序号第二次握手由服务器确认客户端序号并告知自己的初始序号第三次握手由客户端确认服务器序号。至少需要三次交互才能完成这一双向确认。3.3.3 为什么不是四次握手从纯理论的角度看四次握手也可以建立连接但会造成不必要的开销。在第二次握手中服务器把自己的 SYN 和对客户端 SYN 的 ACK 合并到一个报文段里发送这就是所谓的「捎带确认」可以减少一次网络往返。既然三次已经足够双向确认就没有必要再多一次。一个常见的理解误区是「三次握手是因为双方都要发一次 SYN、发一次 ACK所以应该是四次」。这个想法本身没错但关键在于服务器的 ACK 和 SYN 可以在同一次发送中合并因此最终只需要三次。3.3.4 初始序列号为什么随机TCP 的初始序列号 ISN 并不是从 0 或 1 开始而是由操作系统通过一定的算法动态生成。这样做有多个原因避免干扰历史连接如果每次连接的初始序号都固定那么网络上滞留的旧报文就可能与新建连接的序号混淆造成数据错乱。随机化可以降低这种概率。提高安全性如果攻击者能预测初始序号就可能伪造 TCP 报文进行会话劫持。使用难以预测的 ISN 可以增加攻击难度。现代系统通常结合时钟、随机数和哈希函数生成 ISN。区分连接实例一个四元组源 IP、源端口、目的 IP、目的端口可能被复用随机序号有助于区分不同时间建立的连接。3.3.5 SYN 洪泛攻击SYN 洪泛是一种经典的拒绝服务攻击它巧妙利用了三次握手过程中服务器需要为半开连接分配资源的特点。服务器收到 SYN 后进入 SYN_RCVD 状态并会把该连接放入「半连接队列」。攻击者伪造大量不存在的源 IP向服务器发送海量 SYN 报文。服务器会为每个 SYN 建立半连接并回复 SYN ACK但由于源 IP 是伪造的服务器永远收不到第三次握手的 ACK这些半连接会占据队列和内存资源。当半连接队列被占满后正常的连接请求也会被拒绝服务器就失去了服务能力。常见的防御手段包括SYN Cookie服务器不立即为 SYN 分配资源而是根据连接信息计算一个 Cookie 放进 SYN ACK 的序号中。只有收到携带正确 Cookie 的第三次握手 ACK 后才真正分配资源建立连接。缩短 SYN 超时时间让半连接更快地从队列中清除。增大半连接队列长度提升抗攻击能力但只是缓解手段。防火墙限流在网络入口处按源 IP 或总量对 SYN 报文进行限速和过滤。3.4 TCP 四次挥手四次挥手用于正常终止一个 TCP 连接。因为它涉及双向关闭且每次关闭都需要独立确认所以通常需要四次交互。3.4.1 四次挥手过程假设由客户端主动发起关闭第一次挥手客户端发送 FIN 报文段FIN 标志置 1表示「我没有数据要发送了请求关闭连接」。发送后客户端进入 FIN_WAIT_1 状态。第二次挥手服务器收到 FIN 后回复 ACK 报文段确认号 ack 客户端序号 1表示「我知道你要关闭了」。发送后服务器进入 CLOSE_WAIT 状态。客户端收到 ACK 后进入 FIN_WAIT_2 状态。此时客户端到服务器的方向已经关闭但服务器可能还有数据要发给客户端因此服务器到客户端的方向仍然保持。第三次挥手服务器把剩余数据发送完毕后也发送 FIN 报文段表示「我的数据也发完了可以关闭了」。发送后服务器进入 LAST_ACK 状态。第四次挥手客户端收到服务器的 FIN 后回复 ACK 报文段作为确认。发送后客户端进入 TIME_WAIT 状态。服务器收到 ACK 后立即进入 CLOSED 状态。客户端需要等待 2MSL 后才会真正进入 CLOSED 状态。状态变化总结如下阶段发送方报文发送后状态接收方状态第一次挥手客户端FINFIN_WAIT_1收到后进入 CLOSE_WAIT第二次挥手服务器ACKCLOSE_WAIT客户端收到后进入 FIN_WAIT_2第三次挥手服务器FINLAST_ACK客户端收到后进入 TIME_WAIT第四次挥手客户端ACKTIME_WAIT服务器收到后进入 CLOSED3.4.2 为什么挥手需要四次三次握手时服务器可以把 SYN 和 ACK 合并发送因此只需要三次。但挥手时服务器第二次挥手只回 ACK不能同时发 FIN。原因是客户端发出 FIN 只代表客户端不再发送数据但服务器可能还有数据没发完需要继续发送。所以服务器的 ACK 和 FIN 在时间上是分开的不能合并必须等待服务器把剩余数据发送完毕后再发送 FIN。这就是为什么挥手需要四次。3.4.3 为什么主动关闭方要等待 2MSLMSL 即报文最大生存时间是任何报文段在网络中能够存活的最长时间通常为 30 秒到 2 分钟。客户端发送完最后一个 ACK 后进入 TIME_WAIT 状态并等待 2MSL 才关闭。这样设计有两个主要原因第一确保最后一个 ACK 能够到达服务器。如果这个 ACK 在传输中丢失服务器会因为没有收到确认而重传 FIN。客户端在 TIME_WAIT 期间可以收到重传的 FIN并再次回复 ACK从而保证连接被双方正确关闭。如果客户端不等待直接关闭那么服务器重传的 FIN 就永远得不到确认服务器会一直处于 LAST_ACK 状态无法释放。第二让旧连接的所有报文都从网络中消失。等待 2MSL 可以保证本连接产生的所有报文段都已失效并离开网络从而避免它们干扰之后在同一四元组上新建的连接。一个方向上一个 MSL 可以保证最晚发出的报文也已经被接收或丢弃两个方向合计就是 2MSL。3.4.4 大量 TIME_WAIT 状态的问题在服务器端如果大量连接由服务器主动关闭就会出现大量 TIME_WAIT 状态的连接。这些连接虽然不消耗太多内存但会占用本地端口资源。对于需要频繁创建和关闭连接的场景例如短连接高并发的代理服务器TIME_WAIT 过多会导致端口耗尽从而无法建立新连接。常见的优化手段包括开启端口复用 SO_REUSEADDR、调整 TIME_WAIT 时长、使用长连接减少连接的创建和销毁、以及将主动关闭方调整为客户端等。需要注意的是TIME_WAIT 状态是 TCP 协议为可靠性付出的必要代价通常不能简单地彻底取消只能在特定条件下优化。3.5 TCP 如何保证可靠传输TCP 的可靠性建立在多个机制协同工作的基础之上主要包括序号与确认应答、超时重传、校验和、滑动窗口、流量控制和拥塞控制。下面逐一展开。3.5.1 序号与确认应答TCP 把应用层传来的数据看作一个字节流并为每一个字节编号这个编号就是序号。发送方每发送一段数据都会在 TCP 首部中填写该段数据第一个字节的序号。接收方收到数据后会回复一个 ACK 报文确认号表示「我已经收到了这个序号之前的所有数据请从该序号开始继续发送」即期望收到的下一个字节的序号。例如发送方发送了序号为 100、长度为 100 字节的数据那么这段数据覆盖序号 100 到 199。接收方收到后回复 ack 200表示 200 之前的数据都已收到。通过这种方式发送方可以明确知道哪些数据已经被对方接收。序号和确认号为 TCP 提供了「按序到达」和「重复检测」的基础。接收方根据序号对乱序到达的报文段进行排序并根据确认号告知发送方缺失的部分。3.5.2 超时重传发送方每发送一个报文段都会启动一个重传定时器。如果在定时器超时之前没有收到该报文段的确认发送方就认为该报文丢失并重新发送。超时重传是 TCP 最基础的可靠性保障。关键问题在于超时时间 RTO 的设置。如果 RTO 太短正常报文可能因为网络延迟较大而被误判为丢失导致不必要的重传浪费带宽如果 RTO 太长数据真正丢失后需要等待很久才能重传影响传输效率。TCP 通过测量报文段的往返时间 RTT 来动态计算 RTO。早期使用简单的平均往返时间现代实现通常采用 Jacobson 算法综合考虑 RTT 的加权平均值和偏差使 RTO 能够适应网络的波动。3.5.3 快速重传超时重传的缺点是等待时间较长。快速重传机制可以让发送方更快地发现报文丢失接收方每收到一个乱序报文段就立即重复发送对最后一个按序到达字节的 ACK。如果发送方连续收到 3 个相同的 ACK就认为对应的下一个报文段已经丢失立即重传而不必等待重传定时器超时。例如发送方依次发送序号为 1、2、3、4、5 的报文段其中 2 丢失。接收方收到 1 后回 ACK 2收到 3 后发现不是期望的 2于是再次回 ACK 2收到 4、5 时也各回一次 ACK 2。发送方连续收到 3 个 ACK 2就可以判断报文 2 丢失并立即重传。快速重传通常与拥塞控制中的快恢复算法配合使用。3.5.4 校验和TCP 首部包含校验和字段覆盖伪首部、TCP 首部和数据。接收方收到报文后重新计算校验和并与首部中的值比对如果发现不一致说明报文在传输过程中出现了比特错误接收方会直接丢弃该报文相当于视为丢失。之后依靠重传机制来恢复。3.5.5 面向字节流与粘包问题TCP 是面向字节流的应用层写入的数据在 TCP 看来只是一串连续的字节TCP 不保证每次读取都能得到与写入时相同的边界。发送方多次调用 send 可能会被合并成一个报文段发送也可能会被拆分成多个报文段接收方一次 recv 可能收到半个逻辑消息也可能收到多个逻辑消息拼在一起。这就是所谓的「粘包」和「拆包」问题。解决粘包问题通常由应用层负责常见方案有固定长度消息每个消息长度固定不足部分填充。长度前缀在消息开头加上表示消息长度的字段接收方先读长度再按长度读取数据。分隔符在消息之间加入特殊分隔符接收方按分隔符切分。自定义协议结合长度字段和消息类型定义完整的应用层协议。这里也是 TCP 与 UDP 的一个重要区别UDP 面向报文天然保留消息边界不存在粘包问题但存在丢包和乱序问题TCP 面向字节流保证了可靠和有序却模糊了消息边界。四、TCP 滑动窗口、流量控制与拥塞控制4.1 滑动窗口机制如果 TCP 每发送一个报文段都必须等待确认后才发送下一个这种「停止-等待」方式的效率会非常低。为了解决这个问题TCP 引入了滑动窗口机制允许发送方在未收到确认的情况下连续发送多个报文段。窗口大小指的是发送方在未收到确认之前最多还能发送的字节数。发送方维护一个发送窗口窗口内的数据可以连续发送。每收到一个确认窗口就向前滑动腾出空间容纳新的数据。例如发送窗口大小为 4 个报文段发送方可以一次性发出 1、2、3、4 四个报文段不需要等每个都确认。收到对 1 的确认后窗口向前滑动可以继续发送第 5 个报文段。这样可以充分利用网络带宽显著提高吞吐量。发送窗口的大小由两个因素共同决定接收方的接收能力通过接收窗口 rwnd 通告和网络的承载能力通过拥塞窗口 cwnd 度量。发送窗口取两者的较小值。接收窗口由流量控制机制调节拥塞窗口由拥塞控制机制调节。4.2 流量控制流量控制的目的是防止发送方发送速度过快导致接收方来不及处理而被数据淹没。它是一种端到端的控制完全由接收方主导。接收方在每次回复 ACK 时会在 TCP 首部的窗口大小字段中填写自己当前可用的接收缓冲区大小即接收窗口 rwnd。发送方根据这个值调整发送窗口确保在途数据量不超过接收方的处理能力。如果接收方缓冲区快满了它会通告一个较小的窗口发送方就放慢发送如果接收方处理顺利缓冲区空间变大它会通告一个较大的窗口发送方可以加快发送。极端情况下接收方通告窗口为 0发送方必须停止发送数据。窗口为 0 时还存在一个细节当接收方腾出空间后会主动发送一个窗口更新报文通知发送方。但如果这个更新报文在传输中丢失双方就会陷入僵局发送方等待窗口更新接收方以为已经通知过了。为了防止这种情况发送方在窗口为 0 时会启动「持续定时器」周期性地发送探测报文询问接收方窗口是否恢复。4.3 拥塞控制概述流量控制解决的是「接收方处理不过来」的问题而拥塞控制解决的是「网络本身处理不过来」的问题。即使接收方缓冲区足够大如果网络中的路由器排队过长、链路带宽耗尽数据仍然会大量丢失。拥塞控制的目标就是避免给已经拥塞的网络雪上加霜。TCP 通过维护一个拥塞窗口 cwnd 来实现拥塞控制。发送窗口 min(rwnd, cwnd)。拥塞窗口的大小由发送方根据网络状况动态调整当网络畅通时逐步增大发送速率当检测到拥塞时迅速降低发送速率。如何判断网络发生了拥塞TCP 主要依据两个信号一是超时重传说明网络拥塞比较严重报文完全丢失二是连续收到 3 个重复 ACK说明个别报文丢失但网络整体可能仍然能够传递数据。针对这两种不同严重程度的信号TCP 采取不同的回调策略。拥塞控制算法经历了长期演进经典版本包括慢启动、拥塞避免、快重传和快恢复四个部分合称 Tahoe 和 Reno 算法。现代 Linux 内核还实现了 CUBIC、BBR 等更先进的算法。本文先讲清楚经典算法这是面试考察的重点。4.4 慢启动慢启动并不是指发送速度一直很慢而是指拥塞窗口从一个较小的初始值开始然后按指数增长快速试探网络的承载能力。连接刚建立时cwnd 初始为 1 个 MSS。每收到一个 ACKcwnd 就增加 1 个 MSS。由于发送方可以一次发出 cwnd 大小的数据收到这一批数据的 ACK 后cwnd 就会翻倍。因此慢启动阶段 cwnd 的增长规律是1、2、4、8、16……呈指数增长。虽然起点很低但增长速度非常快。慢启动阶段会持续到出现拥塞信号或者 cwnd 达到慢启动门限 ssthresh。当 cwnd 达到 ssthresh 后就进入拥塞避免阶段改用更温和的线性增长。4.5 拥塞避免拥塞避免阶段的目标是让 cwnd 缓慢增长避免过快触发拥塞。此时 cwnd 的增长方式变为每经过一个完整的往返时间 RTTcwnd 增加 1 个 MSS。也就是说不再每收到一个 ACK 就翻倍而是线性增长。拥塞避免阶段中如果发生超时重传说明网络拥塞非常严重TCP 会采取激烈措施把 ssthresh 设置为当前 cwnd 的一半但不小于 2 个 MSS。把 cwnd 重置为 1 个 MSS。重新开始慢启动。这种处理方式快速、彻底能够迅速缓解网络压力但代价是吞吐量会瞬间跌到很低然后重新爬升。这体现了 TCP 拥塞控制的基本思想加法增大、乘法减小。4.6 快重传与快恢复超时重传代价较大因为超时往往意味着网络已经严重拥塞。而连续收到 3 个重复 ACK 时虽然某个报文丢失了但后续报文仍然能够到达接收方说明网络并未完全瘫痪。此时可以不把 cwnd 降到最低而是采取更温和的快恢复策略。当发送方收到 3 个重复 ACK 时立即重传丢失的报文段这就是快重传。执行快恢复把 ssthresh 设置为当前 cwnd 的一半然后把 cwnd 也设置为这个新值即减半而不是降到 1。之后直接进入拥塞避免阶段线性增长。快重传和快恢复合在一起避免了在「个别报文丢失但网络尚可」的情况下过度降低发送速率从而保持了较高的吞吐量。这是 TCP Reno 相对 Tahoe 的重要改进。用伪代码总结经典拥塞控制的核心逻辑初始状态: cwnd 1 MSS ssthresh 较大初始值 state 慢启动 慢启动阶段: 每收到一个 ACK: cwnd cwnd 1 MSS 如果 cwnd ssthresh: 进入拥塞避免阶段 如果发生超时: ssthresh cwnd / 2 cwnd 1 MSS 重新进入慢启动 拥塞避免阶段: 每经过一个 RTT: cwnd cwnd 1 MSS 如果发生超时: ssthresh cwnd / 2 cwnd 1 MSS 重新进入慢启动 收到 3 个重复 ACK 时: ssthresh cwnd / 2 cwnd ssthresh 快重传丢失报文 直接进入拥塞避免阶段需要说明的是上述是经典 Reno 算法的简化描述。现代网络环境复杂Linux 内核默认使用 CUBIC 算法Google 还提出了基于带宽和时延测量而非丢包信号的 BBR 算法。但理解经典算法是理解这些现代算法的基础也是面试的主要考察范围。五、TCP 与 UDP 对比5.1 核心区别一览TCP 和 UDP 的差异可以归结为设计目标的不同下面用表格做系统对比对比维度TCPUDP连接方式面向连接通信前需要三次握手无连接直接发送数据报可靠性可靠保证数据完整、有序、不重复不可靠不保证送达、顺序和去重传输方式面向字节流面向报文首部开销最小 20 字节最大 60 字节固定 8 字节传输效率相对较低需要握手、确认、重传等开销相对较高开销小、无连接建立时延通信模式仅支持一对一全双工支持一对一、一对多、多对一、多对多支持广播和多播拥塞控制有完整的拥塞控制机制无拥塞控制发送速率由应用决定流量控制有通过滑动窗口和接收窗口实现无适用场景需要可靠传输的场景如网页、文件、邮件、数据库时延敏感或允许丢包的场景如直播、语音、游戏、DNS5.2 如何选择 TCP 还是 UDP选择传输层协议时可以按以下判断流程思考数据完整性是否至关重要如果丢失任何一段数据都会导致结果错误比如文件传输、网页加载、数据库同步通常选择 TCP。实时性是否优先于完整性如果数据晚到比不到更糟糕偶尔丢失可以容忍比如视频通话、在线游戏、实时监控通常选择 UDP。是否需要广播或多播如果需要把同一份数据同时发给多个接收者TCP 无法做到只能考虑 UDP。连接数量是否庞大且频繁大量短连接场景下 TCP 的握手和挥手开销可能成为瓶颈可以评估基于 UDP 的自研协议或 QUIC。是否愿意自己实现可靠性如果既想要 UDP 的低延迟和灵活性又需要可靠性可以考虑 QUIC 这类在 UDP 之上实现可靠传输的协议。没有绝对的好协议只有适合场景的协议。TCP 的复杂是它追求可靠性的必然代价而 UDP 的简单是它追求效率的体现。面试中回答这类问题时切忌只说「UDP 快所以好」或「TCP 可靠所以好」要结合具体业务场景分析。六、高频面试题精讲这一部分把 TCP 和 UDP 相关的经典面试题集中梳理一遍给出答题要点和容易踩坑的地方。建议先尝试自己回答再对照要点查漏补缺。6.1 为什么建立连接是三次挥手关闭连接是四次挥手建立连接时服务器可以在回复 SYN ACK 时把对客户端 SYN 的确认和自己的 SYN 合并到一个报文段中所以三次就能完成。关闭连接时客户端发送 FIN 只表示它不再发送数据但服务器可能还有未发送完的数据。因此服务器只能先回 ACK等自己的数据发完后再单独发 FINACK 和 FIN 在时间上分离无法合并所以需要四次。答题核心建连时 ACK SYN 可以捎带合并断开时 ACK 与 FIN 不能合并。6.2 为什么主动关闭方要进入 TIME_WAIT 状态两个原因一是保证最后一个 ACK 能可靠送达服务器如果 ACK 丢失服务器会重传 FINTIME_WAIT 期间客户端可以再次确认二是让旧连接的所有报文从网络中消失避免干扰同一四元组上的新连接。TIME_WAIT 时长为 2MSL。常见追问TIME_WAIT 太多怎么办可以从端口复用、调整参数、使用长连接、调整主动关闭方等角度回答。6.3 如果已经建立了连接客户端突然故障了怎么办TCP 通过保活定时器来处理这种情况。服务器如果在较长时间内没有收到客户端的任何数据会周期性地发送探测报文。如果连续多次探测都没有响应服务器就认为客户端已经不可达从而关闭连接。需要强调的是保活机制不是 TCP 规范强制要求的不同系统的默认参数也不同而且默认探测间隔通常较长。生产环境中更推荐在应用层实现心跳机制以便更快、更可控地发现对端故障。6.4 什么是 SYN 攻击如何防范SYN 攻击利用三次挥手中服务器为 SYN 分配半连接资源的特点伪造大量源 IP 发送 SYN耗尽服务器的半连接队列使正常请求无法建立连接。防范手段包括 SYN Cookie、缩短半连接超时时间、增大队列长度、防火墙限流等。其中 SYN Cookie 是面试中经常被追问的机制需要能够解释其「延迟分配资源」的核心思想。6.5 TCP 粘包是什么怎么解决TCP 是字节流协议没有消息边界应用层多次发送的数据可能在传输层被合并或拆分导致接收方无法正确还原原始消息边界。解决方案由应用层负责常见的有定长消息、长度前缀、分隔符和自定义协议。答题时注意区分UDP 面向报文本身没有粘包问题粘包问题的根源在于字节流没有边界而不是 TCP 丢失了数据。6.6 TCP 为什么可靠可靠性的实现依赖多个机制序号与确认应答保证数据有序和可确认超时重传和快速重传保证丢失数据能够恢复校验和保证数据不被错误接收滑动窗口提高效率流量控制防止接收方过载拥塞控制防止网络过载。面试时应答出这一整套机制而不是只提「重传」。6.7 说说拥塞控制的四个算法慢启动cwnd 从 1 个 MSS 开始指数增长拥塞避免cwnd 按每个 RTT 线性增长快重传收到 3 个重复 ACK 立即重传快恢复收到 3 个重复 ACK 时 cwnd 和 ssthresh 减半后直接进入拥塞避免。超时则 cwnd 降到 1 重新慢启动。答题要点要说清楚两种拥塞信号超时和 3 个重复 ACK分别触发不同的处理逻辑超时更严重处理更激进。6.8 TCP 和 UDP 可以同时绑定同一个端口吗可以。因为 IP 首部中的协议号区分了上层协议操作系统在定位套接字时会把协议类型也纳入匹配。一个 TCP 套接字和一个 UDP 套接字可以绑定相同的 IP 和端口互不影响。6.9 什么是全双工、半双工和单工TCP 是典型的全双工通信双方可以同时发送和接收数据两个方向上的数据流相互独立这也是为什么断开连接需要四次挥手。半双工是指同一时刻只能有一个方向发送例如对讲机单工是指数据只能沿一个方向传输例如广播电台。6.10 DNS 用的是 TCP 还是 UDPDNS 主要使用 UDP 的 53 端口进行查询因为查询报文短小使用 UDP 延迟低。但当响应数据超过 512 字节无法放入单个 UDP 报文时DNS 会改用 TCP 进行传输。此外区域传送等对可靠性要求高的场景也会使用 TCP。因此标准答案是通常用 UDP必要时用 TCP。七、实战分析一次完整的 TCP 通信前面分别拆解了各个机制下面把它们串起来看一次典型的「客户端请求网页」过程中TCP 和 UDP 分别扮演什么角色。7.1 域名解析阶段用户在浏览器输入网址后浏览器需要先把域名解析为 IP 地址。这个 DNS 查询通常通过 UDP 发送到 DNS 服务器的 53 端口。如果响应过大则可能切换为 TCP。这个阶段体现了 UDP 在短小、时延敏感的查询场景中的优势。7.2 建立 TCP 连接拿到 IP 后客户端向服务器 80 端口发起 TCP 连接。双方经过 SYN、SYNACK、ACK 三次握手建立连接。客户端和服务器各自生成随机初始序号完成双向能力确认。7.3 发送 HTTP 请求连接建立后客户端发送 HTTP 请求数据。TCP 将请求数据切分为合适的报文段填上序号后发出。发送窗口由接收窗口和拥塞窗口共同决定数据可以批量发送而不必逐段等待。7.4 可靠传输与拥塞控制服务器收到请求后开始返回响应。传输过程中如果出现丢包发送方会根据超时或重复 ACK 触发重传同时拥塞控制算法会动态调整发送速率。如果接收方缓冲区紧张流量控制会通过通告窗口让发送方放慢速度。7.5 关闭连接响应发送完毕后服务器或客户端发起 FIN 关闭连接经过四次挥手完成双向关闭主动关闭方进入 TIME_WAIT 状态等待 2MSL。整个过程中UDP 负责解析域名的短查询TCP 负责承载 HTTP 的可靠传输两者各司其职。理解了这个完整链路再回看 TCP 和 UDP 的各种特性会更有整体感。八、总结TCP 和 UDP 是传输层最核心的两个协议也是计算机网络面试中绕不开的重点。UDP 简单高效无连接、不可靠、面向报文、开销小、支持广播多播适合 DNS、实时音视频、在线游戏、设备发现等对时延敏感或允许丢包的场景。TCP 复杂而可靠面向连接、面向字节流通过序号、确认、重传、滑动窗口、流量控制和拥塞控制等一系列机制保证数据完整有序地到达适合网页、文件、邮件、数据库等对可靠性要求高的场景。从应试角度看需要重点掌握的内容包括TCP 报文段格式三次握手的过程、原因和异常场景四次挥手的过程、TIME_WAIT 的意义TCP 可靠性机制滑动窗口与流量控制以及慢启动、拥塞避免、快重传、快恢复四个拥塞控制算法。从工程角度看还需要理解粘包问题的成因与解决方案、TIME_WAIT 过多的优化、SYN 洪泛的防御以及在不同业务场景下如何选择传输层协议。最后记住一句话UDP 的快来自简单TCP 的可靠来自复杂。理解它们各自的取舍比背诵结论重要得多。
延伸阅读

更多相关文章

2026/9/18 21:53:05

Redis ACL 权限控制:从共享密码到最小权限实战

1. 从一次线上事故聊聊为什么需要 ACLRedis 6.0 的 ACL 机制,我是等到线上真出了事才回头认真啃的。在那之前,我们那套缓存集群里所有业务线共用一个requirepass,密码写在配置中心的明文条目里,谁都能KEYS *,谁都能FLU…

2026/9/18 21:53:05

勇闯前后端 Week

开篇:Week2 学习地图如果把 Week1 看作是搭好前后端学习的地基,那么 Week2 就是正式开始盖楼的一周。Week1 里我们认识了 HTML、CSS 的基础语法,也初步接触了 JavaScript 的变量、函数和简单的事件绑定,同时在 Node.js 环境里跑通…

2026/9/18 22:58:07

PyWxDump环境配置完全指南:4条命令跑起来,3件事用得安全

PyWxDump环境配置完全指南:4条命令跑起来,3件事用得安全 【免费下载链接】PyWxDump 删库 项目地址: https://gitcode.com/GitHub_Trending/py/PyWxDump 照着文档装完,终端里一敲 wxdump info 就抛 ImportError,这是装完 Py…

2026/9/18 22:58:07

给 Codex 的 Skill 链,TaoToken 只补 Base URL

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/18 22:58:07

PHP+uniapp构建智能举报系统:DFA敏感词过滤与工单闭环实践

做这个项目之前,我去调研过辖区派出所的举报登记流程。接待窗口放着一个厚厚的登记本,民警一边听群众口述一边手写,遇到电话举报就顺手记在便签纸上。一天下来几十条线索,格式五花八门,地址写“老菜场旁边”这种模糊位…

2026/9/18 22:58:07

Cursor 挂 DBHub MCP 操作 MySQL,模型 Base URL 指到 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/18 22:58:07

VSCODE插件十大推荐,这次让Codex走TaoToken替我挑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/18 22:53:07

ollama 在 Ubuntu 装不上,OpenClaw 改走 TaoToken 通道行不行

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/18 14:13:01

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/18 0:01:09

Google Colab 实战:运行模型、数据加载与报错排查

1. 为什么我劝你先搞懂 Colab 的运行模型1.1 Colab 到底是什么,跟本地跑代码差在哪Google Colab 简单说就是一台跑在浏览器里的 Linux 虚拟机,你打开一个 Notebook,背后就连上了一台带 GPU 的远程机器。你在单元格里敲的每一行 Python&#x…

2026/9/18 0:01:09

C语言数据类型与表达式详解

1. C语言数据与数据类型概述在C语言编程中,数据是程序处理的核心对象。理解数据的分类和特性是掌握C语言的基础。C语言中的数据主要分为四大类:常量、变量、表达式和函数。这些数据类型构成了C语言程序的基本元素,每种类型都有其独特的特性和…

2026/9/18 0:01:09

SQL时间字段指定时间段查询:区间语义、索引与时区避坑

上周排查一个线上问题&#xff0c;用户反馈"昨天的订单一条都没查到"&#xff0c;但数据库里明明躺着两千多条。最后定位下来&#xff0c;不是数据丢了&#xff0c;也不是接口挂了&#xff0c;而是那个查询条件把时间段写成了> 2024-05-20 00:00:00 AND < 2024…

2026/9/18 14:13:03

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行&#xff0c;Type-C接口算是典型的“看着简单&#xff0c;做起来全坑”的东西。光引脚就24个&#xff0c;高低速信号、电源、控制线全部塞在一个小小的连接器里&#xff0c;如果PCB布局不做规划&#xff0c;打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/18 14:13:02

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/18 14:13:02

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码