这是本节的多页打印视图。
点击此处打印.
返回本页常规视图.
传输层
本章是计算机网络中的重点,需熟练掌握TCP的滑动窗口机制、连接断开与建立、流量和拥塞控制。
学习思维导图
# 传输层
## 提供的服务
- 传输层功能
- 寻址和端口
- 无连接和面向连接服务
## UDP协议
- UDP数据报
- UDP校验
## TCP协议
- TCP段
- 连接管理
- 可靠传输
- 流量控制
- 拥塞控制
传输层功能
- 数据分段与重组:传输层将上层应用层提供的数据流划分为较小的数据段,以便在网络中传输。在接收端,传输层负责将这些数据段重新组装成完整的数据流,以交付给应用层。
- 端口标识与多路复用:传输层使用端口号来标识不同的应用程序或服务。当多个应用程序同时运行时,传输层可以将它们的数据段混合在一起传输,并在接收端根据端口号将数据分发给正确的应用程序,从而实现多路复用。
- 会话管理:传输层还可以支持会话管理,包括建立、维护和终止与远程主机之间的通信会话。这是通过传输层协议中的握手和挥手过程来实现的,例如TCP握手过程。
- 差错检测与纠正:传输层可以检测并纠正数据传输过程中的错误,确保数据的完整性和正确性。这通常涉及使用校验和和纠错码等技术。
1 - TCP
TCP 是计算机网络中重点,需要熟练掌握 TCP 的可靠传输机制,包含连接建立和断开、流量控制、拥塞控制,常常在选择题和大题中出现。
TCP 特点
- 面向连接:发送数据前后需要分别通过三次握手和四次挥手进行连接的建立和断开。
- 可靠交付:保证数据传输的无差错、不丢失、不重复、有序。
- 面向字节流:以滑动窗口的形式对字节按照顺序进行发送和接收。
- 全双工:通信双方在一个 TCP 连接中都可以发送和接收数据。
TCP 首部
- 源端口号(Source Port):16 位字段,指示发送端的端口号。
- 目标端口号(Destination Port):16 位字段,指示接收端的端口号。
- 序列号(Sequence Number):32 位字段,用于标识 TCP 报文段中第一个数据字节的序列号。这个字段用于实现 TCP 的可靠性机制,如数据的按序传递和重传。
- 确认号(Acknowledgment Number):32 位字段,如果设置了 ACK 标志位,该字段包含了期望接收的下一个数据字节的序列号。这个字段用于确认已经成功接收的数据。
- 数据偏移(Data Offset):4 位字段,指示 TCP 首部的长度,以 32 位字为单位。这个字段用于指示首部的长度,因为 TCP 首部长度可以变化,根据选项的存在而变化。
- 保留(Reserved):6 位字段,保留供未来使用,目前必须设置为 0。
- 控制标志位(Flags):TCP 报文段的控制标志,共有 6 个标志位,它们分别是:
- URG(紧急指针有效位):用于指示紧急数据。
- ACK(确认位):用于指示确认号字段有效。
- PSH(推送位):用于指示接收端应立即交付数据给应用层,而不需要等待缓冲区满。
- RST(复位位):用于强制释放连接,重置连接状态。
- SYN(同步位):用于建立连接,用于初始化序列号。
- FIN(终止位):用于关闭连接。
- 窗口大小(Window Size):16 位字段,指示发送端的可用接收窗口大小。接收端可以根据这个字段的值来告诉发送端可以发送多少数据而不会导致拥塞。
- 校验和(Checksum):16 位字段,用于检测 TCP 首部和数据部分的传输中的错误。
- 紧急指针(Urgent Pointer):16 位字段,仅当 URG 标志位设置时才有效。用于指示紧急数据的末尾位置。
- 选项(Options):可选字段,用于包含一些额外的控制信息,如最大报文段长度、时间戳等。长度可变,最长可达 40 字节。
- 填充(Padding):根据选项字段的长度而变化,用于确保 TCP 首部的总长度是 32 位的倍数。
三次握手
- 第一次握手(SYN-SENT):
- 发送方:将 SYN(同步)标志位设置为 1,表示发起连接请求。
- 序列号(Sequence Number):这是一个 32 位字段,用于标识发送方的 初始序列号(ISN,Initial Sequence Number),用于后续的数据传输。ISN 是一个随机数,用于防止连接重放攻击。
- 确认号(Acknowledgment Number):在第一次握手中,确认号字段被设置为 0,因为此时还没有确认数据的传输。
- 第二次握手(SYN-RECEIVED):
- 接收方:接收到第一次握手的 TCP 报文段后,将 SYN 标志位设置为 1,表示同意建立连接。
- 序列号(Sequence Number):接收方生成自己的初始序列号(ISN),并将其放入序列号字段。
- 确认号(Acknowledgment Number):此时确认号字段被设置为发送方的初始序列号加 1,表示接收到了第一次握手中的序列号。
- 第三次握手(ESTABLISHED):
- 发送方:接收到第二次握手的 TCP 报文段后,将 SYN 标志位设置为 0(因为连接已经建立),并将 ACK(确认)标志位设置为 1,表示确认接收到了第二次握手中的序列号。
- 序列号(Sequence Number):发送方生成一个新的序列号,用于后续的数据传输。
- 确认号(Acknowledgment Number):此时确认号字段被设置为接收方的初始序列号加 1,表示接收到了第二次握手中的序列号。
第三次握手可以携带应用层数据么?
当然可以,你可以想一下,如果发送方还需要收到第三次握手的确认才可以发送数据的话,不就变成四次握手了么,这是不合理的。
不同的 TCP 实现对此有不同的处理方式,有的 TCP 实现是不会将数据放到第三次握手的报文中,有的则会,正确的协议实现对于这两种情况应该都能够正确处理。
四次挥手
- 客户端发送连接关闭请求
- 客户端首先决定不再发送数据,并希望关闭连接。
- 客户端向服务器端发送一个 TCP 报文,其标志位中包含 FIN(Finish)标志,表示客户端已经完成数据的发送任务。
- 客户端进入 FIN-WAIT-1 状态,等待服务器的确认。
- 服务器端确认客户端的关闭请求
- 服务器端接收到客户端的 FIN 报文,知道客户端不再发送数据。
- 服务器端向客户端发送一个 ACK(Acknowledgment)报文作为确认,表示它已收到了客户端的关闭请求。
- 服务器端进入 CLOSE-WAIT 状态,表示服务器端已经完成数据的发送任务,但仍然可以接收来自客户端的数据。
- 服务器端关闭连接
- 服务器端完成了数据的发送任务后,也想要关闭连接。
- 服务器端向客户端发送一个 FIN 报文,告知客户端它已经完成了数据的发送,并请求关闭连接。
- 服务器端进入 LAST-ACK 状态,等待客户端的确认。
- 客户端确认服务器端的关闭请求
- 客户端接收到服务器端的 FIN 报文后,确认服务器端的请求。
- 客户端向服务器端发送一个 ACK 报文作为确认。
- 此时客户端进入 TIME-WAIT 状态,等待足够的时间,以确保服务器端收到了确认,然后再关闭连接。
第一次挥手一定是客户端发起么?
第一次挥手是由发起连接关闭的一方发送的,通常情况下是客户端发送。但在某些特殊情况下,服务器端也可以主动发起连接关闭,不过这种情况相对较少见。
滑动窗口机制
上图是滑动窗口的简图,滑动窗口代表当前 发送方正在发送 以及 接收方正在接收的 数据窗口,数据窗口是所有数据中的一部分。
每当发送方收到接收方的 ACK 确认后,滑动窗口就会向前滑动。这样,窗口中新位置允许新的数据发送
滑动窗口的大小表示发送方在未收到接收方确认(ACK)的情况下,最多可以发送多少字节的数据。窗口大小由接收方决定,并通过 ACK 报文中的窗口字段告知发送方。
绝对下标和序列号的概念区别
绝对下标(Absolute Number)
指的是在整个 TCP 会话期间,数据字节在传输流中的位置,其大小无上限。可以把它想象成一个 TCP 连接中从第一个字节开始的整体计数器。例如,如果一个 TCP 连接传输了 5000 字节的数据,那么这些数据的绝对下标范围是从 1 到 5000。
序列号(Seqno,Sequence Number)是一个 32 位的非负数(unsigned),是 TCP 报文段中实际使用的一个字段,从一个随机的初始序列号(ISN)开始计数。
在 TCP 发送和接收数据时,其需要将 序列号 和 绝对下标 进行转换,假设第一次握手使用的序列号为 ISN
,那么绝对下标 index
对应的序列号为 (index + 1 + ISN) & UINT32_MAX
。
如果接收方接收到的序列号为 seqno
,那么对应的绝对下标为 (seqno - ISN - 1 + UINT32_MAX) % UINT32_MAX + n * UINT32_MAX
,其中这里 n
为一个整数,取决于滑动窗口在 [0, UINT32_MAX]
的区间内移动了几个来回。
以上大家思考一下,不会具体考察,但是思考过程可以帮助大家理清楚这两个概念,并且能够加深对于滑动窗口的理解。
可靠传输机制
TCP 的可靠传输通过多种机制共同实现,下文将对三个关键机制进行介绍。
序列号 和 确认号
序列号(seqno, sequence number) 和 确认号(ackno, acknowledge number) 是 TCP 首部的两个字段,TCP 协议通过 序列号 来记录目前已经发送了哪些数据,通过 确认号 记录哪些数据已经被接收方所接收。
发送方发送序列号 和 接收方返回确认号 的交互可能存在以下几种情况:
- 如果发送的数据段丢失了,接收方不会发送更新的确认号,这会最终导致发送方超时并重传丢失的数据段。
- 如果数据段到达了接收方,但是是乱序的,接收方将持续发送最后一个正确序列号的确认,提示发送方其中有数据段需要重新传输。
- 如果数据段到达了接收方,并且是按顺序的,接收方发送一个新的确认号,提示发送方到目前为止的所有数据都已正确接收。
超时重传
TCP 协议在发送一个 数据段(segment) 时,它会记录目前正在传输的 segment,并为每一个 segment 设置一个定时器。
如果某个 segment 的定时器超时了,就说明发送方在 超时时间阈值 内没有接收到该 segment 的确认,发送方就会触发超时重传(Retransmission Timeout),重新发送超时的 segment。
超时重传的时间时如何确定的?(了解即可)
超时重传的时间 Timeout 可以通过如下公式计算得到:
$$
\begin{align*}
\text{\small Timeout} &= \text{\small EstimatedRTT} + 4*\text{\small DevRTT} \\
\text{\small EstimatedRTT} &= (1-\alpha) * \text{\small EstimatedRTT} + \alpha * \text{\small SampleRTT} \\
\text{\small DevRTT} &= (1-\beta) * \text{\small DevRTT} + \beta * \left|\text{\small SampleRTT} - \text{\small EstimatedRTT}\right|
\end{align*}
$$
SampleRTT 是每一次报文往返时间的样本,EstimatedRTT 是加权平均的往返时间,DevRTT 是往返时间的偏差,而 $\alpha$ 和 $\beta$ 是权重,通常取值为 $\alpha=0.125, \beta=0.25$。
校验和
TCP 首部包含一个校验和(Checksum)字段,用于检测数据在传输过程中的任何变化。如果接收方检测到校验和错误,该数据段会被丢弃,然后接收方会要求发送方重传该数据段。
TCP 的校验和计算方法和 IP校验和计算方法 一致,不过两者校验的范围和目的有所不同。
其IP校验和只针对IP头部进行校验,主要用于检测数据在传输过程中由于网络故障等原因造成的错误。
而TCP校验和不仅要校验TCP头部,还要校验TCP载荷(即数据部分)。因此,TCP校验和能提供更全面的错误检测。
流量控制
TCP(Transmission Control Protocol)流量控制是一种机制,用于确保在网络中的发送方和接收方之间协调数据传输速率,以防止接收方不堪重负并避免数据包的丢失。TCP 流量控制的主要目标是保证数据的可靠传输,同时有效地利用可用的网络带宽。
TCP 通过 滑动窗口机制 来实现流量控制:发送方根据接收方通告的窗口大小发送数据,而接收方根据自己的处理速度和可用内存来控制窗口大小。
- 窗口大小(Window Size):TCP 流量控制使用窗口大小来管理数据流的速率。窗口大小表示发送方可以在没有接收方确认的情况下发送的未被确认的数据量。窗口大小由接收方通过 TCP 报文中的通告窗口字段通知发送方。
- 滑动窗口的调整:窗口大小是动态调整的,它会根据网络条件和接收方的状态而变化。如果接收方的缓冲区快满了,通告窗口大小可能会减小,以减缓发送速率;如果接收方的缓冲区有足够的空间,通告窗口大小可能会增大,以提高发送速率。
- 零窗口控制:如果接收方的缓冲区已满,它可以将窗口大小设置为零,表示不接受任何数据。发送方会注意到这一点并暂停数据的发送,直到接收方准备好接收数据。
TCP 的发送窗口可以按照逻辑划分为四个部分:
- 已经发送并且被确认的数据(字节流)
- 已经发送但还没有被确认
- 尚且还没有发送
- 暂时不可以发送
其中第 2、3 个部分构成 TCP 的发送窗口,当发送方收到 ackno 在第 2 个部分内的确认报文时,调整滑动窗口的大小后向前移动滑动窗口,并且发送接下来可以发送的数据。
TCP 的接收窗口可以按照逻辑划分为四个部分:
- 已经被应用层接收的数据
- 已经被 TCP 接收,但是还没有被应用层接收的数据
- 还没有接收到的数据
- 还不可以接收到的数据
拥塞控制
tcp 的拥塞控制指的是 tcp 限制传输数据的速率,进而防止注入过多的数据到网络中,进而造成网络链路过载。
大家需要了解,tcp 不是一个 “自私” 的算法,一段链路上可以同时包含很多 tcp 连接,tcp 的拥塞控制的目的是尽量去实现一个总体的最优,而不是个体的最优。当 tcp 检测到数据传输出现拥塞之时,即一段时间内没有接收到一些确认,它就会降低自己传输数据的速率。
需了解如下的TCP拥塞控制算法:
1. 慢开始 (slow start)
慢开始是 TCP 连接开始时的一个阶段,相较于直接以较高的速率发送数据,慢开始会以一个较低的速率开始,然后逐步试探当前网络传输的能力,以指数的速率增加发送速率。慢开始的流程如下:
- 初始化:当一个 TCP 连接开始时,拥塞窗口
cwnd
设置为一个很小的值,通常是 1MSS
(最大段大小)。 - 指数增长:对于每个收到的
ACK
, cwnd
会增加一个 MSS
。这意味着每个 RTT
(往返时间) cwnd
都会翻倍,导致了指数增长。 - 转换阈值:当
cwnd
达到 ssthresh
(慢开始阈值)时, TCP
会从慢开始模式转换到拥塞避免模式。
什么是MSS?
MSS 是 Maxium Segment Size 的简称,即最大段大小。MSS 通常是根据网络路径的MTU(最大传输单元)来确定的,MTU是网络层上一种数据包最大尺寸的限制,常见的MSS值为1460字节(MTU 1500字节减去IP头部和TCP头部的大小)。
2. 拥塞避免 (congestion avoidance)
- 线性增长:在这个阶段,每收到一个 ACK,
cwnd
增加 1/cwnd
的大小。这导致了每个 RTT
, cwnd
只增加约一个 MSS
,这是一个线性的增长。 - 拥塞检测:如果发生了超时或者收到三个重复的
ACK
(意味着网络中的数据分段丢失),则认为发生了网络拥塞。此时, ssthresh
会被设置为当前 cwnd
的一半,并将 cwnd
重新设置为 1MSS
,然后重新进入慢开始阶段。
3. 快速重传 (Fast Retransmit) 和 快速恢复 (Fast Recovery)
传统的TCP重传是基于重传计时器的:当计时器到期而没有收到ACK时,TCP会重新发送数据(超时重传)。然而,在有高带宽或低延迟的网络中,等待这个计时器到期可能是低效的。
快速重传 机制是当发送方连续收到三个重复的ACK(表示同一个数据段)时,它会立即重传下一个待确认的数据段,而不是等待重传计时器到期。这三个重复的ACK是网络中丢失一个分段的一个早期指示。
一旦触发了快速重传,TCP进入 快速恢复 模式,按照书上的说法,触发了快速重传后,ssthresh
和 cwnd
都被设定为快速重传前 cwnd
值的一半,然后执行拥塞避免算法。
但是在实际 TCP 的实现中 ssthresh
被设定为当前 cwnd
(拥塞窗口)的一半。同时, cwnd
也会被设定为 ssthresh
加上三个 MSS
(最大段大小),然后执行如下策略:
cwnd
的增加:在快速恢复期间,每当收到一个重复的 ACK
, cwnd
都会增加一个分段的大小。这是为了用新的数据分段平衡可能在传输路径中出现的丢失。- 退出快速恢复:当发送方接收到一个新的、非重复的
ACK
,这表示之前丢失的分段已被成功接收。这时, TCP
会退出快速恢复模式,并将 cwnd
设置为 ssthresh
的值,然后进入拥塞避免阶段。
这里注意一下即可,考试考到的话按照书中方式计算 cwnd
。
总结一下:
- 当
cwmd < ssthresh
时,使用慢开始算法,swnd
以指数增长 - 当
cwmd >= ssthresh
时,使用拥塞避免算法,swnd
线性增长 - 当在 RTO 内没有收到发送的某个分组的确认时
- 如果启动了快速恢复,则设置
cwnd = ssthresh = cwnd / 2
,开始使用拥塞控制算法 - 如果没有启动快速恢复,则设置
ssthresh = cwnd / 2
, cwnd = 1
,开始使用慢开始算法
- 如果启用了快速重传,并且收到 3 个与先前重复的 ACK(总共收到 4 个相同的 ACK),则不用等待超时器 RTO 结束,可以马上重传该数据包,cwnd 可能会减少(这里不考察)
窗口大小
初始窗口大小?
TCP连接的初始窗口大小可以根据TCP/IP协议栈的实现和操作系统的配置而有所不同。通常情况下,初始窗口大小是根据TCP的初始拥塞窗口(Initial Congestion Window,ICW)来确定的。
RFC 6928建议了一种用于确定TCP连接初始拥塞窗口大小的算法,该算法是根据实验和观察得出的最佳实践。根据这个RFC,初始拥塞窗口大小(ICW)的推荐值为10个MSS (了解即可)。
发送窗口的大小?
发送窗口大小为拥塞窗口和接收窗口中的较小值,swnd = min(cwnd, rwnd)
,当发送方收到来自接收方的确认报文时,会根据其中的 window 字段来调整 rwnd
大小,也会根据收到的确认信息或者超时去调整 cwnd
的大小。当 cwnd
或者 rwnd
变化时,会调整 swnd
的大小。
接收窗口的大小?
接收方会根据自身处理能力和缓冲区的情况来动态调整窗口大小。如果接收方的应用程序不能及时处理接收到的数据,或者接收方的缓冲区已经满了,它就会减小窗口大小,以通知发送方降低发送速率。
2 - UDP
了解UDP的概念和应用,对比与TCP的不同,可能在选择题中考察。
UDP数据报
UDP(User Datagram Protocol)首部的长度固定为8个字节(64位),不论UDP携带的数据量大小如何,其首部都保持不变。UDP首部的各个字段如下:
- 源端口(Source Port):占用2个字节(16位),用于标识发送方应用程序的端口号。
- 目标端口(Destination Port):占用2个字节(16位),用于标识接收方应用程序的端口号。
- 长度(Length):占用2个字节(16位),指示UDP数据报的总长度,包括首部和数据。因此,最小长度为8字节。
- 校验和(Checksum):占用2个字节(16位),用于检测UDP数据报在传输过程中是否受到损坏。
UDP校验
UDP(User Datagram Protocol)使用一个16位的校验和字段来检测数据在传输过程中是否受到了损坏。UDP校验和是一种简单的错误检测机制,它用于验证UDP数据报的完整性,但不提供数据的恢复功能。以下是UDP校验和的工作原理:
- 校验和计算:在发送端,UDP计算校验和。计算的过程包括以下步骤:
- 数据报中的所有16位字(包括UDP首部和数据部分)被分成16位的块。
- 这些块被依次加和,得到一个32位的中间结果。
- 将32位的中间结果分成两个16位的字,将它们相加,直到最终得到一个16位的校验和。
- 将计算出的16位校验和存储在UDP首部的校验和字段中。
- 校验和验证:在接收端,UDP接收数据报后,它也会计算校验和,使用与发送端相同的算法。然后,它将接收到的校验和与计算得到的校验和进行比较:
- 如果接收到的校验和与计算得到的校验和匹配,数据被认为是完整的。
- 如果校验和不匹配,数据报被认为已经受损,并且通常会被丢弃。
UDP特点
- 无连接性:UDP是一种无连接的协议,这意味着在发送数据之前,发送方和接收方之间不建立连接。每个UDP数据报都是独立的,没有先后顺序的要求。
- 轻量级:UDP非常轻量级,因为它不涉及连接建立和维护,也不包括复杂的拥塞控制算法。这使得UDP非常适用于低延迟和高吞吐量的应用。
- 无序性:UDP数据报在传输过程中不保持顺序。这意味着发送方发送的多个UDP数据报可能以不同的顺序到达接收方,并且接收方需要自行处理数据的顺序问题。
- 不可靠性:UDP不提供可靠性。它不保证数据的传输成功,也不负责重新发送丢失的数据。如果数据在传输过程中丢失或损坏,接收方将不会收到任何通知,并且需要根据应用程序的要求自行处理这些问题。
- 广播和多播:UDP支持广播和多播,允许一个UDP数据报同时发送到多个接收方。
- 用途:UDP常用于需要低延迟和快速数据传输的应用程序,如实时音视频传输、在线游戏、网络广播等。它也常被用于一些特定的应用层协议,如DNS(Domain Name System)和DHCP(Dynamic Host Configuration Protocol)。