5 运输层¶
5.1 运输层概述¶
在计算机网络中,物理层、数据链路层和网络层共同解决了主机之间通过异构网络互联的问题,实现了主机到主机的通信。
然而,实际进行通信的真正实体是运行在通信两端主机中的应用进程(如图中主机A上的AP1、AP2与主机B上的AP3、AP4)。尽管网络层负责将数据从源主机传输到目的主机,但无法直接支持不同主机上进程之间的通信。
因此,运输层(传输层)的主要任务就是为运行在不同主机上的应用进程提供端到端的逻辑通信服务,即实现进程间的直接通信。运输层协议也被称为端到端协议
TCP/IP 运输层中有两个重要的协议,分别是 TCP 和 UCP
运行在计算机上的进程通常使用进程标识符(Process Identification, PID)进行标识,但由于互联网中的计算机可能运行不同的操作系统(如 Windows、Linux、macOS),而这些系统采用的 PID 格式并不统一,因此无法直接用于跨平台的网络通信。为了使不同操作系统上的应用进程能够基于网络实现互操作,必须采用一种统一的方法来标识和区分应用层进程。
TCP/IP 体系结构中的运输层通过引入端口号来解决这一问题:端口号是一个长度为 16 比特的数值,取值范围为 0~65535,用于唯一标识和区分同一台主机上运行的不同应用进程,从而实现跨平台、跨系统的端到端通信。
端口号只具有本地意义,即端口号只是为了标识本计算机网络协议栈应用层中的各应用进程。在因特网中,不同计算机中的相同端口号是没有关系的,即相互独立。另外,TCP和UDP端口号之间也是没有关系的。
运输层端口号的应用
当用户在PC(192.168.0.1)上输入网址 www.porttest.net 时,由于浏览器只知道该网站的域名而不知道其IP地址,首先会通过DNS服务器(192.168.0.2)进行域名解析:PC向DNS服务器发送查询请求,获取 www.porttest.net 对应的IP地址(如192.168.0.3),这一过程涉及DNS协议和可能的ARP解析。
获得目标IP后,PC开始与Web服务器建立连接:它使用TCP协议发起三次握手,将源端口(如随机分配的50000)和目的端口(通常为HTTP的80端口)写入TCP报文段,并封装成IP数据报(协议字段值为6),通过交换机发送至Web服务器;服务器收到后,根据IP首部的协议字段判断由TCP处理,再依据目的端口号将数据分用到相应的Web服务进程;随后双方进入数据传输阶段,客户端请求网页内容,服务器返回HTML等响应数据
5.2 UDP 和 TCP 的对比¶
UDP是无连接的协议,在数据传输前不需要建立任何逻辑连接,发送方直接将用户数据封装成用户数据报并发送到网络中,接收方收到后即可处理,整个过程简单高效但不保证可靠性;而TCP是面向连接的协议,通信前必须通过“三报文握手”建立逻辑连接,确保双方都准备好通信,之后才进行数据传输,在传输完成后还需通过“四报文挥手”释放连接。
这里的“连接”指的是端到端的逻辑连接关系,而非物理链路
UDP支持单播、多播和广播,TCP仅支持单播
UDP是面向应用报文的,TCP是面向字节流的
UDP是一种无连接、不可靠的传输协议,发送方将数据封装成用户数据报后直接发送,不保证数据是否到达接收方。若数据在传输过程中因网络问题发生丢失、误码或乱序,UDP不会进行重传、纠错或排序,仅丢弃错误数据包
TCP是一种面向连接、可靠的传输协议,通过三次握手建立连接,并在传输过程中实现差错检测、重传机制、流量控制和拥塞控制,能够纠正误码、处理丢失、乱序和重复的数据,确保数据按序、完整地送达接收方,从而向上层提供“面向连接的可靠传输服务”
5.3 TCP¶
5.3.1 TCP报文段的首部格式¶
TCP报文段的首部由固定部分(20字节)和可变选项部分组成
- 序号(Sequence Number) 占32比特,标识本报文段数据载荷的第一个字节在字节流中的序号,用于确保数据按序传输;
- 确认号(Acknowledgment Number) 也占32比特,表示期望收到对方下一个报文段的第一个字节的序号(注意与之前回退N帧之类协议中ACK含义的区分),同时也是对之前已接收数据的确认
- 确认标志位ACK 表示确认号是否有效,只有当ACK=1时确认号才有效,且在TCP连接建立后所有报文段都必须将ACK置为1。
- 数据偏移 占4比特,该字段的取值以4字节为单位。指出TCP报文段的数据载荷部分的起始处距离TCP报文段的起始处有多远,这实际上指出了TCP报文段的首部长度。
- 窗口字段占16比特,以字节为单位,用于指示发送方在当前时刻可以向接收方发送的数据量,即接收方的接收窗口大小。避免接收方因缓冲区满而丢弃数据,从而实现流量控制。
- 检验和 占16比特,用来检查整个TCP报文段在传输过程中是否出现了误码
TCP报文段的检验和字段用于检测传输过程中是否发生错误,其计算基于一个称为“伪首部”的结构。
伪首部由源IP地址、目的IP地址、保留字节(置为0)、协议字段(对TCP为6)和TCP报文段长度组成,它并不实际发送,仅用于校验计算。计算时,首先将TCP首部中检验和字段置为0,然后将伪首部、TCP首部和数据载荷三部分按2字节为单位进行划分,若总长度为奇数则在末尾补一个“全0”字节;接着对所有2字节块执行反码算术求和,并将结果取反码,得到最终的检验和值,写入TCP首部的检验和字段。接收方收到报文后重复该过程,若结果为全0,则说明数据未出错。
伪首部仅仅只用于校验,并不传输
- 同步标志位SYN 用于TCP“三报文握手”建立连接。当SYN=1且ACK=0时,表明这是一个TCP连接请求报文段。对方若同意建立连接,则应在响应的TCP报文段的首部中使SYN=1且ACK=1。
- 终止标志位FIN 用于TCP“四报文挥手”释放连接。当FIN=1时,表明此TCP报文段的发送方已经将全部数据发送完毕,现在要求释放TCP连接。
-
复位标志位RST 用于复位TCP连接。当RST=1时,表明TCP连接中出现严重差错,必须释放连接,然后再重新建立连接。RST置1还用来拒绝一个非法的TCP报文段或拒绝打开一个TCP连接。
-
推送标志位PSH 用于控制数据的立即交付。在正常情况下,发送方可能为了提高效率而延迟发送数据,等待积累更多数据后再发送,接收方也可能会将接收到的数据暂存缓冲区以批量处理;但在交互式通信中(如远程登录),应用进程希望输入的命令能立即被对方处理并返回响应。此时,发送方可通过将PSH置为1,通知接收方“请立即把当前收到的数据交给应用层”,无需等待缓冲区填满。接收方收到PSH=1的报文后,会立即将数据提交给应用进程,从而实现快速响应,提升交互体验。
- 紧急标志位URG和紧急指针字段用于实现紧急数据的快速传输。当URG=1时,表示本报文段包含紧急数据,此时紧急指针字段有效;紧急指针是一个16比特的值,以字节为单位,指出在报文段数据载荷中紧急数据的长度,即从数据起始处到紧急数据末尾的偏移量。发送方将紧急数据“插队”到发送缓存最前面,并立即封装成报文段发送,无需等待缓冲区满。接收方收到URG=1的报文后,会根据紧急指针的值提取出紧急数据,并直接交付给应用进程,而不必在接收缓存中排队等待,从而确保关键信息(如中断信号)能被优先处理
- 选项字段(长度可变,最大40字节)用于扩展协议功能,支持多种高级特性。其中,最大报文段长度(MSS)选项指明TCP数据载荷部分的最大长度(不包括首部),用于协商双方能接受的单个数据段大小,避免IP分片;窗口扩大选项通过增加窗口大小的表示位数,支持更大的接收窗口,从而提高吞吐率和网络利用率;时间戳选项用于精确计算往返时延(RTT),并实现防止序号绕回(PAWS)机制,确保在长时间连接中不会因序号重复而产生混淆;选择确认选项(SACK)则允许接收方告知发送方哪些数据段已收到、哪些丢失,从而实现更高效的重传机制,提升传输可靠性与性能。
- 填充 用于若选项字段的长度加上20字节固定首部的长度不能被4字节整除时,需要填充相应数量的比特0,以确保首部长度能被4字节整除。
5.3.2 “三报文握手”建立TCP连接¶
TCP运输连接有以下三个阶段:
- 通过“三报文握手”来建立TCP连接。
- 基于已建立的TCP连接进行可靠的数据传输。
- 在数据传输结束后,还要通过“四报文挥手”来释放TCP连接。
这一节阐述 “三报文握手” 建立TCP连接的过程
客户端从CLOSED状态开始,主动发送一个SYN=1、seq=x的连接请求报文段,进入SYN-SENT状态;
服务器收到后,若同意建立连接,则回复一个SYN=1、ACK=1、seq=y、ack=x+1的确认报文段,进入SYN-RCVD状态;
TCP规定同步标志位SYN被设置为1的报文段(例如TCP连接请求报文段和TCP连接请求确认报文段)不能携带数据,但要消耗掉一个序号。
TCP规定普通的TCP确认报文段可以携带数据,但如果不携带数据,则不消耗序号。
客户端收到后,再发送一个ACK=1、seq=x+1、ack=y+1的确认报文段,双方均进入ESTABLISHED状态,连接正式建立,之后可进行可靠的数据传输。
我们这个过程是否有疑问,为什么还需要第三个报文段?回应确认之后就直接建立连接不就行了吗
如果采用两次握手,当客户端发送的连接请求报文因网络延迟而未能及时到达服务器时,该报文可能在后续某个时刻突然到达。此时,服务器误认为是新的连接请求,会发送连接确认并进入“连接已建立”状态,但客户端早已放弃该连接,不会回应,导致服务器白白维持一个无效连接,造成资源浪费。
而三次握手通过要求客户端对服务器的确认进行再次确认(ACK),确保双方都明确对方当前有建立连接的意愿,从而有效防止此类问题,避免资源被错误占用。
5.3.2 “四报文挥手”释放TCP连接¶
当客户端主动关闭连接时,它发送一个FIN=1、ACK=1的报文段,进入FIN-WAIT-1状态;
服务器收到后回复ACK=1,确认收到关闭请求,客户端进入FIN-WAIT-2状态,服务器则进入CLOSE-WAIT状态,表示可以继续接收数据但不再发送。
当服务器完成数据传输后,也发送一个FIN=1、ACK=1的报文段,进入LAST-ACK状态;客户端收到后回复ACK=1,进入TIME-WAIT状态,并等待2MSL(最大报文生存时间)以确保最后一个ACK被对方收到,防止旧连接的报文干扰新连接,之后才彻底关闭连接。服务器在收到最终确认后进入CLOSED状态。
TCP 保活计时器
当TCP连接建立后,若双方长时间没有数据交换(例如客户端主机出现故障或网络中断),连接可能处于“空闲但无响应”的状态。为防止此类无效连接长期占用资源,服务器端会启动保活计时器(通常为2小时)。当计时器到期时,服务器开始发送TCP探测报文段,每隔75秒发送一次,用于检测对方是否仍然存活。若连续发送10个探测报文段后仍无客户端响应,服务器将认为客户端所在主机已发生故障,于是主动关闭该连接,释放相关资源。
5.3.3 TCP的流量控制¶
在TCP连接中,发送方可能持续发送大量数据,而接收方的应用程序可能因忙于其他任务,无法及时从接收缓存中取走数据。若发送速度过快,接收缓存将被填满并发生溢出,导致数据丢失。为避免这种情况,TCP提供了流量控制(Flow Control)机制,通过接收方在报文段中通告其当前可用的接收窗口大小(rwnd),动态通知发送方可发送的数据量。发送方根据该窗口值调整发送速率,确保不会超过接收方的处理能力,从而防止接收缓存溢出,保障数据可靠传输。
主机A向主机B发送数据,初始时B的接收窗口(rwnd)为400,表示可接收最多400字节的数据。A连续发送多个报文段,当B接收到前两个报文段后,其接收缓存逐渐填满,可用空间减少,于是向A发送ACK=201、rwnd=300的确认报文,通知A后续只能发送300字节的数据。A收到该信息后,调整发送窗口大小为300,避免继续发送过多数据导致接收方缓存溢出。此后A仅在允许范围内发送数据,确保发送速率与接收方处理能力匹配。
当接收方B的接收缓存已满时,会向发送方A发送一个rwnd=0的报文段,表示暂时无法接收数据;此时A停止发送。
后面 B 向 A 发送一个非零窗口通知,告诉A 可以继续发了。但是如果这个非零窗口通知在传输过程中丢失,B仍处于等待A发送数据的状态,而A因未收到非零窗口通知也一直等待,双方陷入互相等待的死锁局面。
为打破这一僵局,TCP为每个连接设置了持续计时器(Persistent Timer):只要一方收到对方的零窗口通知,就启动该计时器;当计时器超时后,发送方会主动发送一个仅携带1字节数据的“探测报文段”,询问对方当前窗口大小;若对方回复的窗口仍为0,则重新启动计时器;若窗口变为非零,则恢复正常通信。
A发送的零窗口探测报文段到达B时,如果B此时的接收窗口值仍然为0,那么B根本就无法接受该报文段,又怎么会针对该报文段给A发回确认呢?
实际上TCP规定:即使接收窗口值为0,也必须接受零窗口探测报文段、确认报文段以及携带有紧急数据的报文段
如果零窗口探测报文段丢失了,还会打破死锁的局面吗?
回答是肯定的。因为零窗口探测报文段也有重传计时器, 当重传计时器超时后,零窗口探测报文段会被重传。
5.3.4 TCP的拥塞控制¶
在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络性能就要变坏,这种情况就叫作拥塞(congestion)。
计算机网络中的链路容量(带宽)、交换节点中的缓存和处理机等都是网络的资源。
若出现拥塞而不进行控制,整个网络的吞吐量将随输入负荷的增大而下降。
拥塞控制和流量控制
流量控制是指接收方根据其接收缓存的可用空间大小,通过TCP连接中的窗口机制来控制发送方的发送速率,确保接收方不会因处理不过来而丢失数据;
拥塞控制则是为了防止过多的数据注入到网络中,使网络能够承受现有的网络负荷,避免网络出现拥塞甚至崩溃,主要关注的是整个网络的负载情况。
拥塞控制的基本方法可分为开环控制和闭环控制两种。
-
开环控制试图通过良好的设计在系统启动时就防止拥塞的发生,一旦运行便无需中途修正,适用于网络流量特征能够被准确描述且性能要求可事先获得的场景。
-
闭环控制是一种基于反馈的控制方法,主要包括三个步骤:监测网络拥塞发生的时间和地点、将相关信息传递到可采取行动的节点、调整网络运行以缓解拥塞。当网络流量特征难以准确预测或网络不提供资源预留时,适合采用闭环控制。
因特网采用闭环控制方法来应对动态变化的网络环境。
根据拥塞信息的反馈形式,闭环拥塞控制算法可分为显式反馈算法和隐式反馈算法。
- 显式反馈算法由拥塞节点(如路由器)主动向源点发送关于网络拥塞状态的明确信息,例如当路由器因拥塞而丢弃数据报时,会向源主机发送ICMP源抑制报告报文,通知其降低发送速率;这种方式需要网络层参与,因此显式反馈机制必须涉及网络层。
- 隐式反馈算法则由源端通过观察自身在网络中的行为来推断是否发生拥塞,例如通过检测超时重传或往返时间(RTT)的变化来判断网络状况,TCP协议采用的就是这种隐式反馈方式。
因特网主要利用隐式反馈在运输层实现拥塞控制。
四种拥塞控制方法¶
为了集中精力讨论拥塞控制算法的基本原理,假定如下条件:
- 数据是单方向传送的,而另一个方向只传送确认。
- 接收方总是有足够大的接收缓存空间,因而发送方的发送窗口的大小仅由网络的拥塞程度来决定,也就是不考虑接收方对发送方的流量控制。
- 以TCP最大报文段MSS(即TCP报文段的数据载荷部分)的个数作为讨论问题的单位,而不是以字节为单位(尽管TCP是面向字节流的)。
不考虑拥塞控制的话,swnd = rwnd; 不考虑流量控制的话,swnd = cwnd
由于我们不考虑接收方对发送方的流量控制,所以 swnd = cwnd
慢开始是TCP连接初始阶段或发生超时重传后采用的一种拥塞控制策略。其核心思想是从较小的拥塞窗口(cwnd)开始,每经过一个往返时间(RTT),窗口大小按指数方式翻倍增长(即每收到一个确认,cwnd增加1个MSS)
当拥塞窗口增长到慢开始阈值(ssthresh)后,TCP切换到拥塞避免阶段。此时窗口不再指数增长,而是线性增长——每个RTT仅增加1个MSS,以更谨慎的方式试探网络容量。若在此阶段检测到丢包(通常由超时触发),则认为网络已发生拥塞,需大幅降低发送速率。
如果只采用慢开始和拥塞避免的方法,当出现IP数据报首部误码被路由器丢弃,重传计时器超时从而误认为网络出现拥塞,将cwnd的值陡然降低为1并错误地启动慢开始算法,因而降低了传输效率。
采用快重传算法可以让发送方尽早知道发生了个别TCP报文段的丢失。
快重传是一种加速丢包恢复的机制,旨在避免因等待超时而造成不必要的传输延迟。当发送方连续收到三个重复的ACK(即接收方多次确认同一个序列号),即可推断某个中间数据段已丢失,无需等待重传计时器超时,立即重传该丢失报文
与快重传算法配合使用的是快恢复算法,发送方一旦收到3个重复确认,就知道现在只是丢失了个别的报文段,于是不启动慢开始算法,而是执行快恢复算法。
发送方将慢开始门限ssthresh的值和拥塞窗口cwnd的值都调整为当前cwnd值的一半,并开始执行拥塞避免算法。
总结来说,拥塞控制的流程图如下
5.3.5 TCP 可靠传输的实现¶
这个部分的内容实验做过了,内容虽简单但是整理起来比较复杂。基本的内容如下:
TCP 使用以字节为单位的滑动窗口机制来实现可靠传输。
发送方维护一个发送窗口(swnd),接收方维护一个接收窗口(rwnd)。
接收方通过确认报文段中的字段告知发送方:
- ack = n:表示序号 n 之前的所有字节(0 ~ n−1)已正确接收,期望收到序号为 n 的下一个字节。
- rwnd = x:表示当前接收窗口大小为 x 字节,即最多还能接收 x 字节的数据。
放几道题目作为例子
5.3.6 TCP超时重传时间的选择¶
TCP在选择超时重传时间(RTO)时,不能直接使用某次测量得到的往返时间(RTT)样本值,因为单个样本可能受网络波动影响而不稳定。为此,TCP采用加权平均的方法计算平滑的往返时间(RTTs),公式为:
其中 \(0 ≤ α < 1\)。当 \(α\) 接近0时,新样本对RTTs影响小;当α接近1时,影响较大。RFC 6298推荐α取值为1/8(即0.125),以平衡响应速度与稳定性。最终的超时重传时间RTO应略大于该加权平均值RTTs,以避免频繁超时重传,从而提高传输效率和可靠性。
[RFC 6298]建议使用下式来计算超时重传时间RTO:
\(\text{RTT}_D\)为RTT偏差的加权平均值,初始值为\(\text{RTT}_1 / 2\),更新公式为:
推荐β值为1/4(即0.25)。
测量往返实践 RTT 是比较复杂的
通过上述两个例子可以看出:当发送方出现超时重传后,收到确认报文段时是无法判断出该确认到底是对原数据报文段的确认还是对重传数据报文段的确认,也就是无法准确测量出RTT,进而无法正确计算RTO。
Karn 算法指出,只要报文段重传了,就不采用其RTT样本。但是这样也会引入新的问题
设想出现这样的情况:报文段的时延突然增大很多,并且之后很长一段时间都会保持这种时延(这可能是因为网络拓扑发生了变化)。因此在原来得出的RTO内,不会收到确认报文段,于是就重传报文段。但根据Karn算法,不考虑重传的报文段的RTT样本,因此RTO就无法更新,这会导致报文段反复被重传
于是我们修正 Karn 算法: 报文段每重传一次,就把RTO增大一些。典型的做法是将新RTO的值取为旧RTO的2倍。
5.3.8 TCP的选择确认¶
在之前介绍TCP的快重传和可靠传输时,TCP接收方只能对按序收到的数据中的最高序号给出确认。当发送方超时重传时,接收方之前已收到的未按序到达的数据也会被重传。
在 TCP 首部中可以在扩展首部中添加相应的信息,用于指明字节块的信息
SACK相关文档并没有指明发送方应当怎样响应SACK。因此大多数的TCP实现还是重传所有未被确认的数据块。
Review¶
Answer
C,B 回忆一下 TCP 报文段首部中窗口字段的含义,代表的是接受窗口的尺寸,单位是字节
Answer
B 挥手时发送的第四次报文段的 seq = 985,说明挥手时的第一个报文段的 seq = 984,那么接受到的最后一个字节序号就是 983。第一个 SYN 段虽然部携带数据,但是消耗一个序号211,所以发送的字节是 212-983,共 772 个字节
Answer
建立连接的第一个报文段不携带数据,但是消耗一个序号,第三次握手可以携带数据也可以不携带数据(这样就不消耗序号),根据题意,选 C
Answer
让发送窗口达到 8kb(8MSS) 需要 3 RTT,即 9ms,前面一共发了 7kb,剩余可用空间为 9kb
Answer
A, 当前发送窗口大小为 2000B,由于第二个段还没有被确认,所以,还能向主机乙发送一个数据段 1000B
Answer
D,这里的易错点就在于误认为 3000B 可以一次性发出,没有真正理解拥塞窗口。这里第一次只能发送 1000B,因为拥塞窗口为1000B,只有它得到确认之后,才能继续往下发,然后我们发现拥塞窗口扩大了,剩下的报文才能被一次性发掉。
Answer
C 回忆一下数据链路层,以太网 MAC 帧的帧头(6+6+2)和帧尾(4)共 18 字节。IP 数据报首部 20-60字节,UDP 首部 8 字节, TCP 的首部则是 20-60 字节








































