【计算机网络】传输层知识点总结

TCP/IP 是互联网相关的各类协议族的总称,其中包括 TCPUDP,IP,FTP,HTTP,ICMP,SMTP 等。TCP/IP 中两个具有代表性的传输层协议是 TCP 和 UDP:
在这里插入图片描述
传输层:

  • 作用:为上面的应用层提供通信服务,提供应用进程间的逻辑通信
  • 在OSI七层参考模型中,传输层是面向通信部分的最高层用户功能中的最底层
  • 两大重要的功能:1)复用,2)分用。复用是指,在发送端,多个应用进程共用一个传输层。分用是指,在接收端,传输层会根据端口号将数据分派给不同的应用进程
  • 传输层和网络层的区别:1)网络层为不同主机提供通信服务,而传输层为不同主机的不同应用提供通信服务;2)网络层只对报文头部进行差错检测,而传输层对整个报文进行差错检测

传输层的两个主要协议:

  • 传输控制协议 TCP(Transmission Control Protocol)
  • 用户数据报协议 UDP(User Datagram Protocol)

用户数据报协议 UDP

概念: UDP(User Datagram Protocol)在 OSI 模型中处于传输层,属于无连接协议。UDP 尽最大可能交付,没有拥塞控制,面向报文,支持一对一、一对多、多对一和多对多的交互通信。

用户数据报协议 UDP 的特点:

  • 面向无连接(减少开销和发送时延):通信前不需要建立连接,通信结束也无需释放连接
  • 尽最大努力交付:它是尽力而为交付,不能确保每一个数据报都送达
  • 面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加 UDP 首部)
  • 没有拥塞控制(当网络出现堵塞不会使源主机的发送速率降低,这对实时视频会议比较重要,即允许在网络发生堵塞时丢失一些数据,但不允许数据有太大时延)
  • 支持一对一,一对多,多对一,多对多的交互通信(单播、多播、广播),而TCP只支持一对一通信
  • 首部开销小(只有 8 个字节),而TCP头部至少20字节
  • 不可靠性

(1)面向无连接:不需要像 TCP 一样在发送数据前进行三次握手,想发就直接发了,它只是数据的搬运工,不会对数据进行任何拆分和拼接操作。具体来说,就是在发送端,应用层将数据传递给传输层的 UDP 协议,UDP 只会给数据增加一个 UDP 头标识下是 UDP 协议,然后就传递给网络层了;在接收端,网络层将数据传递给传输层,UDP 只去除 IP 报文头就传递给应用层,不会任何拼接操作。
(2)有单播、多播、广播功能:支持一对一、一对多、多对多、多对一的方式传输方式。
(3)面向报文:所谓面向报文就是指UDP数据传输的单位是报文,且不会对数据作任何拆分和拼接操作。在发送端,应用程序给传输层的UDP什么样的数据,UDP不会对数据进行切分,只增加一个UDP头并交给网络层(IP层)。在接收端,UDP收到网络层的数据报后,去除IP数据报头部后遍交给应用层,不会作任何拼接操作。
(4)不可靠性:首先不可靠性体现在无连接上,通信都不需要建立连接,想发就发,这样的情况肯定不可靠。并且收到什么数据就传递什么数据,并且也不会备份数据,发送数据也不会关心对方是否已经正确接收到数据了。再者网络环境时好时坏,但是 UDP 因为没有拥塞控制,一直会以恒定的速度发送数据。即使网络条件不好,也不会对发送速率进行调整。这样实现的弊端就是在网络条件不好的情况下可能会导致丢包,但是优点也很明显,在某些实时性要求高的场景(比如电话会议)就需要使用 UDP 而不是 TCP。UDP只会把想发的数据报文一股脑的丢给对方,并不在意数据有无安全完整到达。
(5)头部开销小:只有 8 字节,相比 TCP 的至少 20 个字节要少得多,在传输数据报文时是很高效的。UDP 头部包括:端口号 + 报文长度 + 数据报文的检验。
(6)没有拥塞控制:UDP始终以恒定的速率发送数据,并不会根据网络拥塞情况对发送速率作调整。这种方式有利有弊。弊端:网络拥塞时有些报文可能会丢失,因此UDP不可靠。优点:有些使用场景允许报文丢失,如:直播、语音通话,但对实时性要求很高,此时UDP还是很有用武之地的。

UDP报文头: 包括源端口,目的端口,整个数据报的长度,整个数据报的检验和。
在这里插入图片描述

传输控制协议 TCP

概念: TCP(Transmission Control Protocol)是 面向连接的提供可靠交付,有流量控制拥塞控制,提供全双工通信,面向字节流,每一条 TCP 连接只能是点对点的(一对一)的传输层通信协议。TCP将用户数据打包成报文段,它发送后会启动一个定时器。

传输控制协议 TCP 的特点:

  • 面向连接的:通信前需要建立连接,通信结束需要释放连接
  • 仅支持单播
  • 提供可靠交付:可靠指的是TCP发送的数据无重复、无丢失、无错误、与发送端顺序一致
  • 面向字节流:把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块
  • 提供拥塞控制
  • 每一条 TCP 连接只能是点对点的:TCP只能提供点到点的通信,而UDP可以任意方式的通信
  • 提供全双工通信:全双工通信指的是TCP的两端既可以作为发送端,也可以作为接收端

(1)面向连接:面向连接,是指发送数据之前必须在两端建立连接。建立连接的方法是“三次握手”,这样能建立可靠的连接。建立连接,是为数据的可靠传输打下了基础。
(2)仅支持单播:每条TCP传输连接只能有两个端点,只能进行点对点的数据传输,不支持多播和广播传输方式。
(3)面向字节流:TCP 不像 UDP 一样那样一个个报文独立地传输,而是在不保留报文边界的情况下以字节流方式进行传输。所谓面向字节流指的是TCP以字节为单位。虽然传输的过程中数据被划分成一个个数据报,但这只是为了方便传输,接收端最终接受到的数据将与发送端的数据一模一样。
(4)可靠传输:对于可靠传输,判断丢包,误码靠的是TCP的段编号以及确认号。TCP为了保证报文传输的可靠,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。
(5)提供拥塞控制:当网络出现拥塞的时候,TCP能够减小向网络注入数据的速率和数量,缓解拥塞。
(6)提供全双工通信:TCP允许通信双方的应用程序在任何时候都能发送数据,因为TCP连接的两端都设有缓存,用来临时存放双向通信的数据。当然,TCP可以立即发送一个数据段,也可以缓存一段时间以便一次发送更多的数据段(最大的数据段大小取决于MSS)。

TCP头部: TCP头部长度有20字节的固定部分,选项部分长度不定,但最多40字节,因此TCP头部在20-60字节之间。
在这里插入图片描述
在这里插入图片描述

  • 源端口(Source Port):数据发起者的端口号
  • 目的端口(Destination Port):数据接收者的端口号(传输层和网络层一大重要区别就是传输层指定了数据报发往的应用进程,因此需要端口号标识)
  • 序列号(Sequence Number,seq):用于在数据通信中解决网络包乱序(reordering)问题,以保证应用层接收到的数据不会因为网络上的传输问题而乱序
  • 确认号(Acknowledgment Number,ack):表示当前主机作为接收端时,期望接收的下一个字节的编号是多少,因此确认号是当前主机已经正确接收的最后一个字节序号(seq)+ 1
  • 报头长度(Offset):存储数据报头部的长度,存储报文头中有多少个32bit,存储长度为 4bit,最大可表示(2 ^ 3+2 ^ 2+2 ^ 1 + 1)x 32bit = 60bytes 的报文头
  • 保留字段(Reserved):均为 0
  • 标识符(TCP Flags):TCP有 7 种标识符,用于表示TCP报文的性质。它们只能为 0 或 1
  • 窗口大小(Window):用于实现TCP的流量控制
  • 检验和(Checksum):该字段检验的范围包括头部和数据这两部分。由发端计算和存储,并由收端进行验证
  • 紧急指针(Urgent Pointer):紧急指针在 URG=1 时才有效,它指出本报文段中的紧急数据的字节数
  • 选项字段(TCP Options):可选的,且长度可变,最长40字节,最常用的选项字段为 MMS:最大报文长度

TCP连接与套接字:

  • TCP连接是一种抽象的概念,表示一条可以通信的链路。每条TCP连接有且仅有两个端点,表示通信的双方。且双发在任意时刻都可以作为发送者和接收者。
  • 一条TCP连接的两端就是两个套接字,套接字 = IP地址:端口号,因此,TCP连接 =(套接字1,套接字2)=(IP1:端口号1,IP2:端口号2)

TCP标识符(TCP Flags): TCP有 7 种标识符,用于表示TCP报文的性质。它们只能为 0 或 1

  • URG = 1:当URG字段被置1,表示本数据报的数据部分包含紧急信息,此时紧急指针有效。
  • ACK = 1:ACK被置 1 后确认号字段才有效,TCP规定,在连接建立后传送的所有报文段都必须把ACK置1。
  • PSH = 1:当接收方收到PSH=1的报文后,会立即将数据交付给应用程序,而不会等到缓冲区满后再提交。一些交互式应用需要这样的功能,降低命令的响应时间。
  • RST = 1:当该值为1时,表示当前TCP连接出现严重问题,必须要释放重连。
  • SYN = 1:SYN在建立连接时使用。当SYN=1,ACK=0时,表示当前报文段是一个连接请求报文。当SYN=1,ACK=1时,表示当前报文段是一个同意建立连接的应答报文。
  • FIN = 1:FIN=1表示此报文段是一个释放连接的请求报文。

1. TCP 三次握手

基本思想:让我知道你已经知道了

TCP 协议中,主动发起请求的一端称为客户端,被动连接的一端称为服务端。不管是客户端还是服务端,TCP 连接建立完后都能发送和接收数据。
在这里插入图片描述
最初服务器和客户端都为 CLOSED 状态。在通信开始前,双方创建各自的传输控制块(TCB)。
服务器创建完 TCB 后遍进入 LISTEN 状态,此时准备接收客户端发来的连接请求。

  • 第一次握手:服务器 B 处于 监听(LISTEN) 状态,此时客户端 A 向 B 发送请求连接报文段。该报文段中 SYN = 1,ACK = 0,seq = x,A 进入 同步已发送(SYN-SENT) 状态,等待服务器确认;(A 问 B 你可以吗?)【SYN = 1,ACK = 0表示该报文段为请求连接报文】【seq = x,x 为本次 TCP 通信的字节流的初始序号,TCP 规定 SYN=1 的报文段不能有数据部分,但要消耗掉一个序号】
  • 第二次握手:服务器 B 收到 A 的连接请求报文段,如果同意建立连接,则向 A 发送连接确认:SYN = 1,ACK = 1,seq = y,ack = x + 1,进入 同步已收到(SYN-RCVD) 状态;(B 告诉 A 我可以)【SYN = 1,ACK = 1表示该报文段为连接同意的应答报文】【seq = y 表示服务端作为发送者时,发送字节流的初始序号】【ack = x+1表示服务端希望下一个数据报发送序号从 x+1 开始的字节】
  • 第三次握手:客户端 A 收到 B 同意连接的应答后,再向 B 发送一次确认报文段,该报文段头部为:ACK = 1,seq = x+1,ack = y+1,客户端发送完这个确认报文后就进入 已建立连接(ESTABLISHED) 状态(A 再告诉 B 我也可以)
  • B 收到 A 的确认后,B 也进入 已建立连接(ESTABLISHED) 状态,完成三次握手

TCP 的三次握手还是挺有意思的,基本思想就是 “让我知道你已经知道” 了。 服务器监听请求,客户端发起连接请求(第一次连接),请求在路上可能存在丢失的风险, 所以当请求到了服务器后如果服务器同意建立连接会给客户端一个回信(第二次连接),告诉它:我已经收到请求,可以连接。 但是回信也存在一个问题,那就是回信能不能到客户端?它需要客户端给他一个回信说我已经收到批准通知了, 如果客户端一直不回复的话意味着客户端没有收到批准通知。 因此客户端一收到批准通知就立马回复(第三次握手):OK 老铁我收到你的批准通知了。至此,三次握手结束。

这种“让我知道你已经知道了”的想法是一种约定俗成的 可靠信息交互的基本方式, 基于此想法构建的信息交互框架叫做协议。

相关解释:

  • 序列号 seq:占 4 个字节,用来标记数据段的顺序,TCP 把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号 seq 就是这个报文段中的第一个字节的数据编号。
  • 确认号 ack:占 4 个字节,期待收到对方下一个报文段的第一个数据字节的序号;序列号表示报文段携带数据的第一个字节的编号;而确认号指的是期望接收到下一个字节的编号;因此当前报文段最后一个字节的编号+1即为确认号。
  • 确认号 ACK(标志位):占 1 位,当 ACK=1 时,表示确认号有效,反之无效。
  • 同步号 SYN(标志位):连接建立时用于同步序号。当 SYN=1,ACK=0 时表示这是一个连接请求报文段。若同意连接,则在响应报文段中使得 SYN=1,ACK=1。因此,SYN=1 表示这是一个连接请求,或连接接受报文。SYN 这个标志位只有在 TCP 建立连接时才会被置 1,握手完成后 SYN 标志位被置 0。
  • 终止号 FIN(标志位):用来释放一个连接。FIN=1 表示此报文段的发送方的数据已经发送完毕,并要求释放运输连接。
  • URG:紧急指针是否有效。为1,表示某一位需要被优先处理。
  • PSH:提示接收端应用程序立即从TCP缓冲区把数据读走。
  • RST:对方要求重新建立连接,复位。

ACK、SYN 和 FIN这些大写的单词表示标志位,其值要么是 1,要么是 0;ack、seq小写的单词表示序号。

2. TCP 四次挥手

TCP连接是双向的,因此在四次挥手中,前两次挥手用于断开一个方向的连接,后两次挥手用于断开另一方向的连接。
在这里插入图片描述

  • 第一次挥手:客户端 A 发送连接释放请求,并停止发送数据,该请求只有报文头,主要参数:FIN = 1,seq = u。此时客户端进入 **终止等待1(FIN-WAIT-1)**状态;【FIN=1表示该报文段是一个连接释放请求】【seq = u,u-1 是 A 向 B 发送的最后一个字节的序号】
  • 第二次挥手:服务器 B 收到 A 的释放请求后发出确认,确认报文包括:ACK = 1,seq = v,ack = u + 1。此时 TCP 处于半关闭状态,服务器进入 **关闭等待(CLOSE-WAIT)**状态,B 能向 A 发数据但 A 不会向 B 发数据。此时 A 进入 **终止等待2(FIN-WAIT-2)**状态,等待 B 传输最后的数据并发送连接释放请求。第二次挥手完成后,A到B方向的连接已经释放,B不会再接收数据,A也不会再发送数据。但B到A方向的连接仍然存在,B可以继续向A发送数据。【ACK=1:除TCP连接请求报文段以外,TCP通信过程中所有数据报的ACK都为1,表示应答】【seq=v,v-1是B向A发送的最后一个字节的序号】【ack = u+1 表示希望收到从第 u+1 个字节开始的报文段,并且已经成功接收了前 u 个字节】
  • 第三次挥手:当 B 不再需要连接时,向 A 发送连接释放请求,请求头:FIN = 1,ACK = 1,seq = w,ack = u + 1,此时 B 进入 **最后确认(LAST-ACK)**状态,等待 A 的确认
  • 第四次挥手:A 收到 B 的请求释放后进行确认,ACK = 1,ack = w + 1,B 进入 CLOSED 状态,A 进入 TIME-WAIT 状态,等待 2 MSL(最大报文存活时间)若没有收到 B 的重发请求的话,就释放连接并进入 CLOSED 状态。

服务器结束 TCP 连接的时间要比客户端早一些。

3. TCP可靠传输的实现

TCP的可靠性表现在:它向应用层提供的数据是无差错的、有序的、无丢失的,简单的说就是:TCP最终递交给应用层的数据和发送者发送的数据是一模一样的。

TCP采用了流量控制拥塞控制连续ARQ等技术来保证它的可靠性。

  1. 超时重传:数据到达接收方,接收方需要发出一个确认应答,表示已经收到该数据段,并且确认序号会说明了它下一次需要接收的数据序列号。如果发送发迟迟未收到确认应答,那么可能是发送的数据丢失,也可能是确认应答丢失,这时发送方在等待一定时间后会进行重传。这个时间一般是2*RTT(报文段往返时间)+一个偏差值。
  2. 窗口控制:TCP会利用窗口控制来提高传输速度,意思是在一个窗口大小内,不用一定要等到应答才能发送下一段数据,窗口大小就是无需等待确认而可以继续发送数据的最大值。如果不使用窗口控制,每一个没收到确认应答的数据都要重发。使用窗口控制,如果数据段1001-2000丢失,后面数据每次传输,确认应答都会不停地发送序号为1001的应答,表示我要接收1001开始的数据,发送端如果收到3次相同应答,就会立刻进行重发;但还有种情况有可能是数据都收到了,但是有的应答丢失了,这种情况不会进行重发,因为发送端知道,如果是数据段丢失,接收端不会放过它的,会疯狂向它提醒…
  3. 拥塞控制:慢启动、拥塞避免、快速重传

停止等待协议(ARQ协议)

ARQ(Automatic Repeat Request)自动重传请求。顾名思义,当请求失败时它会自动重传,直到请求被正确接收为止。这种机制保证了每个分组都能被正确接收。停止等待协议是一种 ARQ 协议。

停止等待协议的原理:

  • 无差错的情况:A向B每发送一个分组,都要停止发送,等待B的确认应答;A只有收到了B的确认应答后才能发送下一个分组
  • 分组丢失 和 出现差错 的情况:发送者拥有超时计时器。每发送一个分组便会启动超时计时器,等待B的应答。若超时仍未收到应答,则A会重发刚才的分组。分组出现差错:若B收到分组,但通过检查和字段发现分组在运输途中出现差错,它会直接丢弃该分组,并且不会有任何其他动作。A超时后便会重新发送该分组,直到B正确接收为止。分组丢失:若分组在途中丢失,B并没有收到分组,因此也不会有任何响应。当A超时后也会重传分组,直到正确接收该分组的应答为止。综上所述:当分组丢失 或 出现差错 的情况下,A都会超时重传分组。
  • 应答丢失 和 应答迟到 的情况:TCP会给每个字节都打上序号,用于判断该分组是否已经接收。应答丢失:若B正确收到分组,并已经返回应答,但应答在返回途中丢失了。此时A也收不到应答,从而超时重传。紧接着B又收到了该分组。接收者根据序号来判断当前收到的分组是否已经接收,若已接收则直接丢弃,并补上一个确认应答。应答迟到:若由于网络拥塞,A迟迟收不到B发送的应答,因此会超时重传。B收到该分组后,发现已经接收,便丢弃该分组,并向A补上确认应答。A收到应答后便继续发送下一个分组。但经过了很长时间后,那个失效的应答最终抵达了A,此时A可根据序号判断该分组已经接收,此时只需简单丢弃即可。

停止等待协议的注意点:

  • 每发送完一个分组,该分组必须被保留,直到收到确认应答为止
  • 必须给每个分组进行编号。以便按序接收,并判断该分组是否已被接收
  • 必须设置超时计时器。每发送一个分组就要启动计时器,超时就要重发分组
  • 计时器的超时时间要大于应答的平均返回时间,否则会出现很多不必要的重传,降低传输效率。但超时时间也不能太长

滑动窗口协议(连续ARQ协议)

连续ARQ协议:在ARQ协议发送者每次只能发送一个分组,在应答到来前必须等待。而连续ARQ协议的发送者拥有一个发送窗口,发送者可以在没有得到应答的情况下连续发送窗口中的分组。这样降低了等待时间,提高了传输效率。(TCP保证其可靠性采用的是滑动窗口协议,停止等待协议是它的简化版)

累计确认:在连续ARQ协议中,接收者也有个接收窗口,接收者并不需要每收到一个分组就返回一个应答,可以连续收到分组之后统一返回一个应答。这样能节省流量。TCP头部的ack字段就是用来累计确认,它表示已经确认的字节序号+1,也表示期望发送者发送的下一个分组的起始字节号。

发送窗口:发送窗口的大小由接收窗口的剩余大小决定。接收者会把当前接收窗口的剩余大小写入应答 TCP 报文段的头部,发送者收到应答后根据该值和当前网络拥塞情况设置发送窗口的大小。发送窗口的大小是不断变化的。
在这里插入图片描述
发送窗口由三个指针构成:p1,p2,p3

  • p1 指向发送窗口(黑色部分)的后沿(左侧),它左边的字节表示已经发送且已收到应答
  • p2 指向尚未发送的第一个字节
  • p3 指向发送窗口的前沿(右侧),它右边的字节尚未发送,且不允许发送

p1-p2 间的字节表示已经发送,但还没收到确认应答。这部分的字节仍需保留,因为可能还要超时重发。p2-p3 间的字节表示可以发送,但还没有发送的字节。发送者每收到一个应答,后沿就可以向前移动指定的字节。此时若窗口大小仍然没变,前沿也可以向前移动指定字节。

接收窗口:接收者收到的字节会存入接收窗口,接收者会对已经正确接收的有序字节进行累计确认,发送完确认应答后,接收窗口就可以向前移动指定字节。如果某些字节并未按序收到,接收者只会确认最后一个有序的字节,从而乱序的字节就会被重新发送。
在这里插入图片描述
连续 ARQ 的注意点:

  1. 同一时刻发送窗口的大小并不一定和接收窗口一样大。虽然发送窗口的大小是根据接收窗口的大小来设定的,但应答在网络中传输是有时间的,有可能t1时间接收窗口大小为m,但当确认应答抵达发送者时,接收窗口的大小已经发生了变化。此外发送窗口的大小还随网络拥塞情况影响。当网络出现拥塞时,发送窗口将被调小。
  2. TCP标准并未规定未按序到达的字节的处理方式。但TCP一般都会缓存这些字节,等缺少的字节到达后再交给应用层处理。这比直接丢弃乱序的字节要节约带宽。
  3. TCP标准规定接收方必须要有累计确认功能。接收方可以对多个TCP报文段同时确认,但不能拖太长时间,一般是0.5S以内。此外,TCP允许接收者在有数据要发送的时候捎带上确认应答。但这种情况一般较少,因为一般很少有两个方向都要发送数据的情况。

流量控制

什么是流量控制?
如果发送者发送过快,接收者来不及接收,那么就会有分组丢失。为了避免分组丢失,控制发送者的发送速度,使得接收者来得及接收,这就是流量控制。

流量控制的目的?
流量控制根本目的是防止分组丢失,它是构成 TCP 可靠性的一方面。

如何实现流量控制?
由滑动窗口协议(连续ARQ协议)实现。
滑动窗口协议既保证了分组无差错、有序接收,也实现了流量控制。

流量控制引发的死锁
当发送者收到了一个窗口为0的应答,发送者便停止发送,等待接收者的下一个应答。但是如果这个窗口不为0的应答在传输过程丢失,发送者一直等待下去,而接收者以为发送者已经收到该应答,等待接收新数据,这样双方就相互等待,从而产生死锁。

持续计时器
为了避免流量控制引发的死锁,TCP 使用了持续计时器。每当发送者收到一个零窗口的应答后就启动该计时器。时间一到便主动发送报文询问接收者的窗口大小。若接收者仍然返回零窗口,则重置该计时器继续等待;若窗口不为0,则表示应答报文丢失了,此时重置发送窗口后开始发送,这样就避免了死锁的产生。

拥塞控制

“拥塞避免”并非指完全能够避免了拥塞。利用以上的措施要完全避免网络拥塞还是不可能的。“拥塞避免”是说在拥塞避免阶段将拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞。

拥塞控制 和 流量控制 的区别?

  1. 拥塞控制:拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况;
  2. 流量控制:流量控制是作用于接收者的,它是控制发送者的发送速度从而使接收者来得及接收。

拥塞控制是针对于网络而言的,它是防止往网络中写入太多分组,从而导致网络拥塞的情况;而流量控制是针对接收者的,它是通过控制发送者的发送速度保证接收者能够来得及接收。

拥塞控制的目的?

  1. 缓解网络压力
  2. 保证分组按时到达

拥塞控制方法:慢开始(slow-start)、拥塞避免(congestion avoidance)、快重传(fast retransmit)和快恢复( fast recovery )。

发送方维持一个拥塞窗口 cwnd ( congestion window )的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞。

发送方控制拥塞窗口的原则是:只要网络没有出现拥塞,拥塞窗口就再增大一些,以便把更多的分组发送出去。但只要网络出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数。

慢开始算法 & 拥塞避免算法

慢开始:当主机开始发送数据时,如果立即所大量数据字节注入到网络,那么就有可能引起网络拥塞,因为现在并不清楚网络的负荷情况。因此,较好的方法是 先探测一下,即由小到大逐渐增大发送窗口,也就是说,由小到大逐渐增大拥塞窗口数值。通常在刚刚开始发送报文段时,先把拥塞窗口 cwnd(congestion window)设置为一个最大报文段 MSS(Maximum Segment Size)的数值。而在每收到一个对新的报文段的确认后,把拥塞窗口数值翻倍。用这样的方法逐步增大发送方的拥塞窗口(cwnd),可以使分组注入到网络的速率更加合理。
在这里插入图片描述
每经过一个传输轮次,拥塞窗口 cwnd 就加倍。一个传输轮次所经历的时间其实就是往返时间RTT。不过“传输轮次”更加强调:把拥塞窗口cwnd所允许发送的报文段都连续发送出去,并收到了对已发送的最后一个字节的确认。

若发送方出现了超时重传,则表明网络出现拥塞。此时:

  • 慢开始门限设为当前发送窗口的一半
  • 拥塞窗口设为 1
  • 启用拥塞避免算法

另外,慢开始的“慢”并不是指cwnd的增长速率慢,而是指在TCP开始发送报文段时先设置cwnd=1,使得发送方在开始时只发送一个报文段(目的是试探一下网络的拥塞情况),然后再逐渐增大cwnd。

为了防止拥塞窗口(cwnd)增长过大引起网络拥塞,还需要设置一个慢开始门限ssthresh状态变量(如何设置ssthresh)。慢开始门限ssthresh的用法如下:

  • 当 cwnd < ssthresh 时,使用慢开始算法
  • 当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法
  • 当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞控制避免算法

慢开始算法的作用:慢开始算法将发送窗口从小扩大,而且按指数级扩大,从而避免一开始就往网络中注入过多的分组从而导致拥塞;它将窗口慢慢扩大的过程其实也在探测网络拥塞情况的过程,当发现出现拥塞时,及时降低发送速度,从而减缓网络拥塞。

拥塞避免算法:让拥塞窗口(cwnd)缓慢地增大,即每经过一个往返时间 RTT 就把发送方的拥塞窗口(cwnd)加 1,而不是加倍。这样拥塞窗口(cwnd)按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。

无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有收到确认),就要把慢开始门限ssthresh设置为出现拥塞时的发送方窗口值的一半(但不能小于2)。然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生 拥塞的路由器有足够时间把队列中积压的分组处理完毕。

如下图,用具体数值说明了上述拥塞控制的过程。现在发送窗口的大小和拥塞窗口一样大。
在这里插入图片描述

  • 当TCP连接进行初始化时,把拥塞窗口cwnd置为1。前面已说过,为了便于理解,图中的窗口单位不使用字节而使用报文段的个数。慢开始门限的初始值设置为16个报文段,即 ssthresh = 16
  • 在执行慢开始算法时,拥塞窗口 cwnd 的初始值为1。以后发送方每收到一个对新报文段的确认ACK,就把拥塞窗口值翻倍,然后开始下一轮的传输(图中横座标为传输轮次)。因此拥塞窗口cwnd 随着传输轮次按指数规律增长。当拥塞窗口cwnd增长到慢开始门限值ssthresh时(即当cwnd=16时),就改为执行拥塞控制算法,拥塞窗口按线 性规律增长
  • 假定拥塞窗口的数值增长到24时,网络出现超时(这很可能就是网络发生拥塞了)。更新后的ssthresh值变为12(即变为出现超时时的拥塞窗口数值24的一半),拥塞窗口再重新设置为1,并执行慢开始算法。当 cwnd=ssthresh=12 时改为执行拥塞避免算法,拥塞窗口按线性规律增长,每经过一个往返时间增加一个MSS的大小

拥塞避免算法的作用:拥塞避免算法使发送窗口以线性方式增长,而非指数级增长,从而使网络更加不容易发生拥塞。

AIMD算法(加法增大乘法减小算法):慢开始算法 和 拥塞避免算法 还有个名称叫做加法增大乘法减小算法。

  • 加法增加:指的是拥塞避免算法,使得发送窗口以线性的方式增长;
  • 乘法减小:指的是不管当前正使用慢开始算法还是拥塞避免算法,只要发生拥塞时,慢开始门限将会变成当前窗口的一半。

快重传算法 & 恢复算法

慢开始算法和拥塞避免算法能保证网络出现拥塞时进行相应的处理,而快重传和快恢复是一种拥塞预防的方式,此时网络可能尚未出现拥塞,但已经有拥塞的征兆,因此得作出一些预防措施。

如果发送方设置的超时计时器时限已到但还没有收到确认,那么很可能是网络出现了拥塞,致使报文段在网络中的某处被丢弃。这时,TCP马上把拥塞窗口 cwnd 减小到1,并执行慢开始算法,同时把慢开始门限值ssthresh减半。这是不使用快重传的情况。

快重传原理:因为TCP具有累计确认的能力,因此接收者收到一个分组的时候不会立即发出应答,可能需要等待收到多个分组之后再同一发出累计确认。但快重传算法就要求,接收者如果接收到一个乱序的分组的话,就必须立即发出前一个正确分组的确认应答,这样能让发送者尽早地知道有一个分组可能丢失。

快重传算法 首先要求接收方每收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时才进行捎带确认。
在这里插入图片描述
接收方收到了M1和M2后都分别发出了确认。现在假定接收方没有收到M3但接着收到了M4。显然,接收方不能确认M4,因为M4是收到的失序报文段。根据 可靠传输原理,接收方可以什么都不做,也可以在适当时机发送一次对M2的确认。但按照快重传算法的规定,接收方应及时发送对M2的重复确认,这样做可以让 发送方及早知道报文段M3没有到达接收方。发送方接着发送了M5和M6。接收方收到这两个报文后,也还要再次发出对M2的重复确认。这样,发送方共收到了 接收方的四个对M2的确认,其中后三个都是重复确认。快重传算法还规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段M3,而不必 继续等待M3设置的重传计时器到期。由于发送方尽早重传未被确认的报文段,因此采用快重传后可以使整个网络吞吐量提高约20%。

快重传算法规定:发送端只要一连收到三个重复的 ACK 即可断定有分组丢失了,就应该立即重传丢失的报文段而不必继续等待为该报文段设置的重传计时器的超时。

快恢复原理:当发送者收到同一个分组的三个确认应答后,就基本可以判断这个分组已经丢失了;这时候无需等待超时,直接执行『乘法减小加法增大』:

  • 将慢开始门限减半
  • 将发送窗口减半(不设为1)
  • 使用拥塞避免算法

与快重传配合使用的是快恢复算法,其过程有以下两个要点:

  1. 当发送方连续收到三个重复确认 ACK 时,就执行“乘法减小”算法,把慢开始门限 ssthresh 减半。这是为了预防网络发生拥塞,但接下来不执行慢开始算法。
  2. 由于发送方现在认为网络很可能没有发生拥塞,因此与慢开始不同之处是现在不执行慢开始算法(即拥塞窗口 cwnd 不设置为1),而是把 cwnd 值设置为慢开始门限 ssthresh 减半后的数值,然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大。

乘法减小:是指不论在慢开始阶段还是拥塞避免阶段,只要出现一次超时(即出现一次网络拥塞),就把慢开始门限值 ssthresh 设置为当前的拥塞窗口值乘以 0.5。当网络频繁出现拥塞时,ssthresh 值就下降得很快,以大大减少注入到网络中的分组数。

加法增大:是指执行拥塞避免算法后,在收到对所有报文段的确认后(即经过一个往返时间),就把拥塞窗口 cwnd 增加一个 MSS 大小,使拥塞窗口缓慢增大,以防止网络过早出现拥塞。

快重传和快恢复的示意图:新的 TCP Reno 版本在快重传之后采用快恢复算法而不是采用慢开始算法
在这里插入图片描述
在采用快恢复算法时,慢开始算法只是在TCP连接建立时和网络出现超时时才使用。采用这样的拥塞控制方法使得TCP的性能有明显的改进。

也有的快重传实现是把开始时的拥塞窗口cwnd值再增大一点,即等于 ssthresh + 3 X MSS 。这样做的理由是:既然发送方收到三个重复的确认,就表明有三个分组已经离开了网络。这三个分组不再消耗网络 的资源而是停留在接收方的缓存中。可见现在网络中并不是堆积了分组而是减少了三个分组。因此可以适当把拥塞窗口扩大了些。

接收方根据自己的接收能力设定了接收窗口rwnd,并把这个窗口值写入TCP首部中的窗口字段,传送给发送方。因此,接收窗口又称为通知窗口。因此,从接收方对发送方的流量控制的角度考虑,发送方的发送窗口一定不能超过对方给出的接收窗口rwnd 。

发送方窗口的上限值 = Min [ rwnd, cwnd ]

  • 当rwnd < cwnd 时,是接收方的接收能力限制发送方窗口的最大值
  • 当cwnd < rwnd 时,则是网络的拥塞限制发送方窗口的最大值

相关面试题

1)为什么用三次握手?

答: 防止失效的连接请求报文段被服务端接收,从而产生错误。如果客户端发送的连接请求在网络中滞留太久,客户端等待一个超时重传时间后,就会重新请求连接。只要有三次握手,服务器虽然收到了两个连接请求,并回发了两个请求确认,但客户端不会回应前一个请求确认,就不会打开这个失效的链接请求。

失效的连接请求:若客户端向服务端发送的连接请求丢失,客户端等待应答超时后就会再次发送连接请求,此时,上一个连接请求就是失效的。

2)为什么不能用两次握手进行连接?

答: 三次握手完成两个重要的功能,既:1)双方都知道彼此已准备好,2)允许双方就初始序列号进行协商,这个序列号在握手过程中进行发送和确认。

如果把三次握手改成两次握手,可能发生死锁。比如:客户端发出去的一个连接请求由于某些原因在网络节点中滞留导致延迟,直到连接释放的某个时间点才到达服务端,但这是一个早已失效的报文,可是这时服务端仍然认为这是客户端的建立连接请求第一次握手,于是服务端回应了客户端,这是第二次握手。但是客户端并不会发来新的数据,服务端就这么傻等着,形成了死锁。

3)如果已经建立了连接,但是客户端突然出现故障了怎么办?

答: TCP 还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为 2 小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔 75 秒钟发送一次。若一连发送 10 个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

4)为什么用四次挥手?

答: 服务器收到客户端发送的FIN 连接释放报文之后,就进入了 CLOSE-WAIT 状态,发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。

5)为什么客户端要先进入TIME-WAIT状态,等待2MSL后才进入CLOSED状态?

答: 为了保证B能收到A的确认应答。若A发完确认应答后直接进入CLOSED状态,那么如果该应答丢失,B等待超时后就会重新发送连接释放请求,但此时A已经关闭了,不会作出任何响应,因此B永远无法正常关闭。

6)为什么连接的时候是三次握手,关闭的时候却是四次握手?

答: 因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

7)为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

答: 虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

8)UDP 和 TCP 有什么区别?
在这里插入图片描述

  • TCP 向上层提供 面向连接的可靠的服务 ,UDP 向上层提供 无连接的不可靠服务,TCP 保证数据顺序,UDP 不保证
  • TCP 传输单位称为TCP报文段,UDP传输单位称为用户数据报
  • 虽然 UDP 并没有 TCP 传输来的准确,但是也能在很多实时性要求高的地方有所作为。对数据准确性要求高,速度可以相对较慢的,可以选用 TCP
  • TCP对应的协议包括:FTP(文件传输协议)、SMTP(邮件传送协议)、HTTP(从Web服务器传输超文本到本地浏览器的传送协议)等。UDP对应的协议包括:DNS(域名解析服务)、SNMP(简单网络管理协议)、TFTP(简单文件传输协议)等。

9)在浏览器中输入 www.baidu.com 后的执行过程?用到哪些层?各层是干什么的?

浏览器要将URL解析为IP地址,解析域名就要用到DNS协议,首先主机会查询DNS的缓存,如果没有就给本地DNS发送查询请求。DNS查询分为两种方式,一种是递归查询,一种是迭代查询。如果是迭代查询,本地的DNS服务器,向根域名服务器发送查询请求,根域名服务器告知该域名的一级域名服务器,然后本地服务器给该一级域名服务器发送查询请求,然后依次类推直到查询到该域名的IP地址。DNS服务器是基于UDP的,因此会用到UDP协议。

得到IP地址后,浏览器就要与服务器建立一个http连接。因此要用到http协议,http协议报文格式上面已经提到。http生成一个get请求报文,将该报文传给TCP层处理,所以还会用到TCP协议。如果采用https还会使用https协议先对http数据进行加密。TCP层如果有需要先将HTTP数据包分片,分片依据路径MTU和MSS。TCP的数据包然后会发送给IP层,用到IP协议。IP层通过路由选路,一跳一跳发送到目的地址。当然在一个网段内的寻址是通过以太网协议实现(也可以是其他物理层协议,比如PPP,SLIP),以太网协议需要直到目的IP地址的物理地址,有需要ARP协议。

1、客户端浏览器通过 DNS 解析到 www.baidu.com 的 IP 地址 220.181.27.48,通过这个 IP 地址找到客户端到服务器的路径。客户端浏览器发起一个 HTTP 会话到 220.181.27.48,然后通过 TCP 进行封装数据包,输入到网络层。
2、在客户端的传输层,把HTTP会话请求分成报文段,添加源和目的端口,如服务器使用80端口监听客户端的请求,客户端由系统随机选择一个端口如5000,与服务器进行交换,服务器把相应的请求返回给客户端的5000端口。然后使用IP层的IP地址查找目的端。
3、客户端的网络层不用关心应用层或者传输层的东西,主要做的是通过查找路由表确定如何到达服务器,期间可能经过多个路由器,这些都是由路由器来完成的工作,我不作过多的描述,无非就是通过查找路由表决定通过那个路径到达服务器。
4、客户端的链路层,包通过链路层发送到路由器,通过邻居协议查找给定IP地址的MAC地址,然后发送ARP请求查找目的地址,如果得到回应后就可以使用ARP的请求应答交换的IP数据包现在就可以传输了,然后发送IP数据包到达服务器的地址。

其中,DNS协议,http协议,https协议属于应用层;TCP/UDP属于传输层;IP协议,ARP协议属于网络层。
在这里插入图片描述


参考资料:
[1] 计算机网络传输层知识点全覆盖
[2] TCP/IP详解–拥塞控制 & 慢启动 快恢复 拥塞避免
[3] TCP的三次握手与四次挥手理解及面试题(很全面)
[4] 一文搞懂 TCP 和 UDP 的区别

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章