运输层
约 3998 字大约 13 分钟
2025-04-14
概述
网络层实现了主机到主机的通信,但是真正通信的实体是位于通信两端主机中的进程,如何为运行在不同主机上的应用进程提供直接的通信服务是运输层的任务,运输层协议又称为端到端协议。
运输层向高层用户屏蔽了下面网络核心的细节,使应用进程看见的就好像是在两个运输实体之间有一条端到端的逻辑通信信道。

端口号
TCP/IP体系的运输层使用端口号来区分应用层的不同应用进程(统一的方法):熟知端口号,0-1023;登记端口号,1024-49151;短暂端口号,49152-65535。[只具有本地意义,为了标识本计算机应用层中的各进程]

UDP和TCP的对比
- 用户数据报协议UDP(User Datagram Protocol)是无连接的,尽最大努力交付(也就是不可靠),不使用流量控制和拥塞控制,对应用层交付的报文直接打包,支持一对一,一对多,多对一,多对多交互通信,首部开销小,仅8字节。
- 传输控制协议TCP(Transmission Control Protocol)是面向连接的,提供可靠交付,使用流量控制和拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块),每一条TCP连接只能有两个端点EP,只能是一对一通信,首部最小20字节,最大60字节。
UDP首部格式

首部字段只有8字节,包块源端口,目的端口,长度,校验和。12字节的伪首部是为了计算校验和临时添加的。
TCP首部格式

- 端口:占16比特,写入端口号,用来标识该TCP报文段的应用进程。
- 序号:占32比特,序号增加到最后一个后,下一个序号就又回到0。指出本TCP报文段数据载荷的第一个字节的序号。
- 确认号:占32比特,确认号增加到最后一个后,下一个确认号就又回到0。指出期望收到对方下一个TCP报文段的数据载荷的第一个字节的序号,同时也是对之前收到的所有的数据的确认。若确认号等于n,则表明到序号n-1为止的所有数据都已正确接收,期望接收序号为n的数据。
- 数据偏移:占4比特,并以4字节为单位。用来指出TCP报文段的数据载荷部分的起始处距离TCP报文段的起始处有多远,实际上指TCP报文段的首部长度。(0101-1111)-->(20-60)
- 确认标志位ACK:当ACK=1时,确认字段才有效,否则无效。TCP规定,在连接建立后所有发送的TCP报文段都必须把ACK置1。
- 同步标志位SYN:在TCP连接建立时用来同步序号。当 SYN=1,ACK=0 时表示这是一个连接请求报文段。若对方同意建立连接,则响应报文中 SYN=1,ACK=1。
- 终止标志位FIN:用来释放TCP连接。当 FIN=1 时,表示此报文段的发送方的数据已发送完毕,并要求释放连接。
- 复位标志位RST:用来复位TCP连接。当RST=1时,表明TCP连接出现了异常,必须释放连接,然后再重新建立连接。RST置1还用来拒绝一个非法的报文段或拒绝打开一个TCP连接。
- **推送标志位PSH:**接收方的TCP收到该标志位为1的报文段会尽快上交应用进程,而不必等待接收缓存都填满后再向上交付。
- **紧急标志位URG:**取值为1时紧急指针字段有效。否则无效。
- **紧急指针:**占16比特,以字节为单位,用来指明紧急数据的长度。当发送方有紧急数据时,可将紧急数据插队到发送缓存的最前面,并立刻封装到一个TCP报文段中运行发送,紧急指针会指出本报文段数据载荷部分包含了多长的紧急数据,紧急数据之后是普通数据。
- 窗口:占16比特,以字节为单位。指出发送本报文段的一方的接收窗口。窗口值作为接收方让发送方设置其发送窗口的依据。这是以接收方的接受能力来控制发送方的发送能力,称为流量控制。
- 校验和:占16比特,首部+数据载荷,要在TCP报文段的前面加上12字节的伪首部。
- 选项(长度可变):
- 最大报文段长度MSS选项:TCP报文段数据载荷部分的最大长度。
- 窗口扩大选项:为了扩大窗口(提高吞吐率)
- 时间戳选项:计算往返时间RTT;处理序号超范围的情况(防止序号绕回PAWS)
- 选择确认选项
- **填充:**由于选项的长度可变,因此使用填充来确保报文段首部能被4整除。
TCP的流量控制
流量控制就是让发送方的发送速率不要太快,保证接收方来得及接收。
- 利用滑动窗口机制可以很方便地在TCP连接上实现对发送方的流量控制。
- TCP接收方利用自己的接收窗口的大小来限制发送方发送窗口的大小。
- TCP发送方收到接收方的零窗口通知(不能发送数据)后,应启动持续计时器。持续计时器超时后,向接收方发送零窗口探测报文。
TCP的拥塞控制
在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络性能就要变坏,这种情况就叫做拥塞(带宽、交换节点中的缓存和处理机都是网络的资源)
若出现拥塞而不进行控制,整个网络的吞吐量将随输入负荷的增大而下降。

TCP主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、快重传、快恢复。
为了方便讨论,假定如下条件:
- 数据是单方向传送,而另一个方向只传送确认。
- 接收方总是有足够大的缓存空间,因而发送方发送窗口的大小由网络的拥塞程度来决定。
- 以最大报文段MSS的个数为讨论问题的单位,而不是以字节为单位。

慢开始和拥塞避免
- 发送方维护一个叫做拥塞窗口cwnd的状态变量,其值取决于网络的拥塞程度,并且动态变化。
- 拥塞窗口cwnd的维护原则:只要网络没有出现拥塞,拥塞窗口就再增大一些;但主要网络出现拥塞,拥塞窗口就减少一些。
- 判断出现网络拥塞的依据:没有按时收到应到达的确认报文(即发生超时重传)
- 发送方将拥塞窗口作为发送窗口,即swnd=cwnd
- 维护一个慢开始门限ssthresh状态变量:
- 当cwnd<ssthresh时,使用慢开始算法
- 当cwnd>ssthresh时,停止使用慢开始算法而改用拥塞控制算法
- 当cwnd=ssthresh时,即可使用慢开始算法,也可使用拥塞控制算法
- 使用拥塞控制算法时,每个轮次只将cwnd加1。如果重传计时器超时,则判断网络很可能出现了拥塞:
- 将ssthresh值更新为发生拥塞控制时cwnd值的一半
- 将cwnd值减小为1,并重新开始执行慢开始算法
- 慢开始是指一开始向网络注入的报文段少,而不是指拥塞窗口cwnd增长速度慢(倍数增加)
- 拥塞避免并非指完全能够避免拥塞,而是指在拥塞避免阶段将拥塞窗口控制为线性规律增长,使网络比较不容易出现拥塞。
有时个别报文段会在网络中丢失,但实际上网络并未发生拥塞,这将导致发送方超时重传,并认为网络发生了拥塞,发送发将拥塞窗口cwnd又设置为最小值1,并错误启动慢开始算法,因而降低了传输效率。采用快重传算法可以让发送方尽早知道发生了个别报文段的丢失。
快重传和快恢复
- 所谓快重传,就是使发送方尽快进行重传,而不是等待超时重传计时器超时再重传。
- 要求接收方不要等待自己发送数据时才进行捎带确认,而是要立即发送确认
- 即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认
- 发送发一旦收到3个连续的重复确认,就将相应的报文段立即重传,而不是等待该报文段的超时重传计时器超时再重传。
- 对于个别丢失的报文段,发送发不会出现超时重传,也就不会误认为出现了拥塞。使用快重传可以使整个网络的吞吐量提高约20%。
- 发送方一旦收到3个重复确认,就知道现在只是丢失了个别的报文段。于是不启动慢开始算法,而执行快恢复算法:
- 发送方将慢开始门限ssthresh值和拥塞窗口cwnd值调整为当前窗口的一半;开始执行拥塞避免算法
- 也有的快恢复实现是把快恢复开始时的拥塞窗口cwnd值再增大一些,即等于新的ssthresh+3
- 既然发送方收到3个重复确认,就表明有3个数据报文段已经离开了网络
- 这3个报文段不再消耗网络资源而是停留在接收方的接收缓存中
- 可见现在网络中不是堆积了报文段而是减少了3个报文段,因此可以适当把拥塞窗口扩大些。

TCP超时重传时间
一个报文段从发送再到接收到确认所经过的时间称为往返时间 RTT,加权平均往返时间 RTTs 计算如下:

其中,0 ≤ a < 1,RTTs 随着 a 的增加更容易受到 RTT 的影响。
超时时间 RTO 应该略大于 RTTs,TCP 使用的超时时间计算如下:

其中 RTTd 为偏差的加权平均值。
TCP的可靠传输
TCP基于以字节为单位的滑动窗口来实现可靠传输。
窗口是缓存的一部分,用来暂时存放字节流。发送方和接收方各有一个窗口,接收方通过 TCP 报文段中的窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其它信息设置自己的窗口大小。
发送窗口内的字节都允许被发送,接收窗口内的字节都允许被接收。如果发送窗口左部的字节已经发送并且收到了确认,那么就将发送窗口向右滑动一定距离,直到左部第一个字节不是已发送并且已确认的状态;接收窗口的滑动类似,接收窗口左部字节已经发送确认并交付主机,就向右滑动接收窗口。
接收窗口只会对窗口内最后一个按序到达的字节进行确认,例如接收窗口已经收到的字节为 {31, 34, 35},其中 {31} 按序到达,而 {34, 35} 就不是,因此只对字节 31 进行确认。发送方得到一个字节的确认之后,就知道这个字节之前的所有字节都已经被接收。

TCP的三次握手

假设 A 为客户端,B 为服务器端。
- 首先 B 处于 LISTEN(监听)状态,等待客户的连接请求。
- A 向 B 发送连接请求报文,SYN=1,ACK=0,选择一个初始的序号 x。
- B 收到连接请求报文,如果同意建立连接,则向 A 发送连接确认报文,SYN=1,ACK=1,确认号为 x+1,同时也选择一个初始的序号 y。
- A 收到 B 的连接确认报文后,还要向 B 发出确认,确认号为 y+1,序号为 x+1。
- B 收到 A 的确认后,连接建立。
三次握手的原因
第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。
客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的连接确认。客户端等待一个超时重传时间之后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。如果有第三次握手,客户端会忽略服务器之后发送的对滞留连接请求的连接确认,不进行第三次握手,因此就不会再次打开连接。

注意:
- TCP的标准规定,SYN = 1的报文段不能携带数据,但要消耗掉一个序号。
- TCP的标准规定,普通的确认报文段如果不携带数据,则不消耗序号。
TCP的四次挥手

以下描述不讨论序号和确认号,因为序号和确认号的规则比较简单。并且不讨论 ACK,因为 ACK 在连接建立之后都为 1。
- A 发送连接释放报文,FIN=1。
- B 收到之后发出确认,此时 TCP 属于半关闭状态,B 能向 A 发送数据但是 A 不能向 B 发送数据。
- 当 B 不再需要连接时,发送连接释放报文,FIN=1。
- A 收到后发出确认,进入 TIME-WAIT 状态,等待 2 MSL(最大报文存活时间)后释放连接。
- B 收到 A 的确认后释放连接。
四次挥手的原因
客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。
TIME_WAIT
客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL。这么做有两个理由:
- 确保最后一个确认报文能够到达。如果 B 没收到 A 发送来的确认报文,那么就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。
- 等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。