
1. 传输层到底解决了什么问题1.1 从“寄快递”理解端到端通信网络分层里传输层是承上启下的关键一层。往下它依赖网络层把数据包送到目标主机往上它要给应用层提供一套好用的通信接口。很多人复习到这里会卡住觉得概念太抽象。我习惯用一个类比网络层像快递公司的干线运输只负责把包裹从A城市的集散中心送到B城市的集散中心至于包裹里装的是什么、收件人到底在不在家、要不要签收它一概不管。传输层就是那个真正跟收件人打交道的角色它要确认对方在不在、包裹有没有丢、顺序对不对。这个类比能解释一个核心问题为什么网络层已经提供了主机到主机的通信还需要传输层因为一台主机上同时跑着浏览器、聊天工具、邮件客户端网络层把数据送到主机后根本分不清该交给哪个程序。传输层通过端口号解决了进程到进程的区分问题通过复用与分用让多个应用共享同一条网络链路。复用就是发送方多个应用进程共用传输层往下发分用就是接收方传输层根据端口把数据交给正确的应用进程。复习传输层脑子里要始终挂着两条主线一条是可靠传输怎么实现另一条是效率怎么保证。围绕这两条主线TCP和UDP走出了完全不同的路。1.2 TCP与UDP的分工不是“好坏”而是“场景”初学者容易把TCP当成“好的”UDP当成“差的”这是个误区。两者是面向不同需求设计的。TCP提供面向连接的、可靠的、基于字节流的服务UDP提供无连接的、尽最大努力交付的、基于报文的服务。对比维度TCPUDP连接方式面向连接需三次握手无连接直接发可靠性确认、重传、排序、去重不保证可靠传输单位字节流数据报首部开销20字节起8字节流量控制有滑动窗口无拥塞控制有无适用场景文件传输、网页、邮件实时音视频、DNS查询选型逻辑很直接如果数据一个字节都不能错比如下载文件、传文档用TCP如果追求低延迟、能容忍少量丢包比如语音通话、直播用UDP。实时场景里丢一帧画面比卡顿两秒的体验好得多重传反而添乱。注意UDP并非“不可靠就不能用”很多实时协议在应用层自己做轻量级的丢包处理把控制权握在自己手里而不是交给传输层。2. TCP可靠传输的三大支柱2.1 滑动窗口让发送方“边走边等”可靠传输最朴素的想法是“发一个等确认再发下一个”这叫停止等待协议。问题是效率太低链路往返时间被白白浪费。滑动窗口的核心思想是发送方可以连续发送多个报文段不必每发一个就停下来等确认。窗口的本质是一段可以连续发送而无需等待确认的序号范围。发送方维护一个发送窗口窗口内的序号可以发送收到确认后窗口向前滑动。这里有个关键点窗口大小决定了流水线的深度。窗口越大能同时在途的未确认数据越多吞吐量越高但对接收方缓冲和网络承载的要求也越高。接收方也有一个接收窗口用来告诉发送方“我还能收多少”。这就是流量控制的来源——接收方通过窗口字段动态调整发送方的发送速率防止自己缓冲区被撑爆。我复习时总结过一句话滑动窗口既是可靠传输的机制也是流量控制的载体一箭双雕。2.2 超时重传时间到底设多长发送方发出报文后启动计时器超时未收到确认就重传。难点在于超时时间怎么定。设太短明明没丢也重传浪费带宽还加重拥塞设太长真丢了要等很久才补延迟高。TCP采用自适应重传时间。它先采样每个报文段的往返时间RTT然后算加权平均往返时间RTTs再算RTT偏差的加权平均RTTd最后超时重传时间RTO RTTs 4×RTTd。这个公式的直觉是以平均往返时间为基准再加上四倍波动幅度作为安全余量。网络抖动越大RTTd越大RTO就越保守。这里有个经典陷阱叫Karn算法重传的报文段不能用来更新RTT采样值。因为你收到的确认分不清是原始报文还是重传报文的如果拿它算RTT会把时间算错。所以重传时不更新RTTs同时每重传一次把RTO翻倍避免在网络拥塞时火上浇油。2.3 选择确认与快速重传别傻等超时超时重传有个天然缺陷必须等到计时器到期。如果发送方连续发了1、2、3、4、5中间2丢了接收方收到3、4、5会一直重复确认“我要2”。发送方收到三个重复确认就知道2大概率丢了不必等超时立刻重传2这叫快速重传。更进一步接收方可以告诉发送方“我收到了哪些不连续的块”这叫选择确认SACK。有了SACK发送方只重传真正丢失的那部分而不是把丢失点之后的所有数据全部重传。这在窗口很大、丢包零散时能省下大量带宽。实操心得复习时把“累计确认”和“选择确认”对比着记。累计确认说“到这个序号为止我全收到了”选择确认说“除了这几块其他我都收到了”。前者简单但可能重传多余数据后者精细但首部开销更大。3. 三次握手与四次挥手别只背流程3.1 三次握手为什么不是两次或四次三次握手的流程大家都背过客户端发SYN服务端回SYNACK客户端再发ACK。但面试和考试爱问“为什么是三次”。两次不够是因为服务端无法确认客户端的接收能力。客户端发SYN服务端回SYNACK如果到此为止服务端不知道客户端到底收没收到自己的SYN。客户端再发一个ACK服务端才能确认“对方既能发也能收”。本质上是双方都要确认自己和对方的收发能力都正常这需要至少三次交互。四次没必要是因为服务端的SYN和ACK可以合并成一个报文发出去省一次交互。所以三次是理论最少且够用的次数。三次握手还顺带完成了序号同步。双方各自随机选一个初始序号通过握手交换并确认为后续可靠传输打好基础。初始序号随机化是为了避免旧连接的残留报文干扰新连接。3.2 四次挥手与TIME_WAIT的存在意义挥手比握手多一次因为TCP连接是全双工的两个方向要分别关闭。主动关闭方发FIN对方回ACK此时一个方向关了对方数据发完后也发FIN主动方回ACK连接才彻底关闭。中间那次ACK和FIN不能合并因为被动关闭方可能还有数据要发。主动关闭方在发完最后一个ACK后要进入TIME_WAIT状态等待2倍报文最大生存时间。这个等待有两个目的一是确保最后一个ACK能到达对方如果丢了对方会重发FIN自己还能再回一次ACK二是让本次连接的所有报文在网络中彻底消失避免干扰使用相同端口的新连接。注意TIME_WAIT是主动关闭方才有服务端如果主动关闭大量连接会积累很多TIME_WAIT占用端口资源。这是高并发服务端要特别关注的调优点。3.3 握手挥手中的状态迁移速记复习状态机时我建议按“谁主动”来分。客户端主动打开CLOSED→SYN_SENT→ESTABLISHED。服务端被动打开CLOSED→LISTEN→SYN_RCVD→ESTABLISHED。主动关闭ESTABLISHED→FIN_WAIT_1→FIN_WAIT_2→TIME_WAIT→CLOSED。被动关闭ESTABLISHED→CLOSE_WAIT→LAST_ACK→CLOSED。其中CLOSE_WAIT是个高频考点也是实战排障重点。如果服务端出现大量CLOSE_WAIT说明对方已经关了但自己迟迟没调用关闭通常是应用层代码没正确释放连接。TIME_WAIT多则通常是主动关闭方属于正常现象但数量过大要考虑连接复用。4. 拥塞控制网络堵车时怎么办4.1 慢启动与拥塞避免的配合流量控制是照顾接收方拥塞控制是照顾整个网络。TCP拥塞控制的核心变量是拥塞窗口cwnd发送方实际能发的数据量取拥塞窗口和接收窗口的较小值。慢启动阶段cwnd从1个报文段开始每收到一个确认就翻倍呈指数增长。名字叫“慢启动”其实增长一点不慢只是起点低。增长到慢启动阈值ssthresh后进入拥塞避免阶段改为每个往返时间加1呈线性增长。这样设计是为了先快速探到网络容量的大致位置再小心逼近。4.2 超时与快重传下的不同反应一旦检测到拥塞TCP要降速。但降速方式取决于怎么发现的拥塞。如果是超时说明网络可能严重拥塞反应要激烈ssthresh设为当前cwnd的一半cwnd直接降到1重新慢启动。如果是收到三个重复确认快重传说明网络还能送回来一些报文拥塞没那么严重反应温和些ssthresh和cwnd都设为当前cwnd的一半然后进入快恢复cwnd从这个值开始线性增长不回到1。拥塞信号ssthreshcwnd后续阶段超时当前cwnd一半降为1慢启动三个重复ACK当前cwnd一半降为一半快恢复这个对比表我复习时反复看因为考试特别爱考两种情况的区别。4.3 从Tahoe到Reno再到现代算法早期TCP Tahoe版本无论超时还是快重传都把cwnd降到1。后来Reno版本引入快恢复区分了两种情况。再往后有NewReno、SACK、CUBIC等改进。CUBIC用三次函数代替线性增长在高带宽长延迟网络里表现更好也是很多现代系统的默认选择。复习时不必深挖每个算法的公式但要理解演进逻辑网络带宽越来越大、延迟越来越高老算法增长太慢填不满管道。新算法都在解决“如何更快地探到并稳定在合适的发送速率”这个问题。5. 那些容易混淆的细节5.1 端口号与套接字的区别端口号是传输层用来标识进程的16位数字范围0到65535。其中0到1023是熟知端口1024到49151是登记端口49152到65535是临时端口。套接字是IP地址加端口号的组合唯一标识网络中的一个通信端点。一条TCP连接由四元组唯一确定源IP、源端口、目的IP、目的端口。这里有个易错点同一个端口可以出现在多条连接里只要四元组不同就行。比如服务端80端口可以同时服务成千上万个客户端因为每个客户端的IP和端口不同。5.2 报文段、数据报、分组别混用不同层的数据单元叫法不同。应用层叫报文传输层TCP叫报文段UDP叫用户数据报网络层叫分组或数据报数据链路层叫帧物理层叫比特。复习时用词准确能避免很多概念混淆。5.3 为什么UDP首部只有8字节UDP首部只有源端口、目的端口、长度、校验和四个字段各2字节。它不做可靠传输、不做流量控制、不做拥塞控制所以不需要序号、确认号、窗口这些字段。首部小意味着开销低、处理快这正是实时应用看重的。校验和是UDP唯一的差错检测手段而且它是可选的。IPv4里可以不算IPv6里强制要算。校验和覆盖首部和数据还加了一个伪首部包含源IP、目的IP、协议号等目的是验证数据确实送到了正确的主机和协议。6. 复习方法与实战排查6.1 用抓包工具把抽象变具体光看书很难真正理解握手挥手。我建议用抓包工具实际抓一次访问网页的过程亲眼看SYN、SYNACK、ACK三个包看序号和确认号怎么变化。再抓一次关闭过程看FIN和ACK的交互观察TIME_WAIT状态持续多久。抓包时重点看几个字段序号、确认号、窗口大小、标志位。把抓到的包和书本流程一一对应抽象概念立刻落地。这比背十遍流程图都管用。6.2 常见问题速查表现象可能原因排查方向大量CLOSE_WAIT应用未关闭连接检查代码连接释放逻辑大量TIME_WAIT主动关闭过多启用连接复用或调整内核参数连接建立慢握手丢包或重传抓包看是否有SYN重传吞吐量上不去窗口太小或拥塞检查窗口字段和丢包率偶发连接失败端口耗尽查看临时端口使用情况6.3 复习节奏建议传输层知识点密集我自己的复习节奏是第一遍通读建立框架知道有哪几块第二遍逐个攻克把滑动窗口、拥塞控制这些硬骨头画图推导第三遍做真题用题目检验哪里还有漏洞第四遍合上书自己复述整个可靠传输的机制链条。推导题一定要动手算。比如给一组RTT采样值自己算一遍RTTs、RTTd和RTO算过一遍比看十遍公式印象深。拥塞窗口的变化过程也要自己画时间轴标出每个阶段cwnd怎么变。我个人在实际操作中的体会是传输层最忌讳死记硬背。把“为什么需要这个机制”“不用它会怎样”这两个问题想清楚大部分知识点都能自己推出来。比如想清楚为什么需要滑动窗口就自然理解了流量控制想清楚为什么需要拥塞控制就自然理解了慢启动和快恢复的分工。复习到能给别人讲明白的程度这一章才算真正拿下。