第三章 传输层

一、TCP概述和TCP段格式

1.TCP概述

TCP(Transmission Control Protocol), 面向连接的, 可靠的, 基于字节流的传输层控制协议

特点 描述
面向连接 应用程序在使用 TCP协议之前,必须先建立TCP连接
在传输数据完毕后,必须释放已经建立的 TCP连接。
每一条TCP连接
只能有两个端点
每一条TCP连接只能是点对点的(一对一)。
提供可靠交付的服务 通过TCP连接传送的数据,无差错、不丢失、不重复,并且按序到达。
提供全双工通信

TCP 允许通信双方的应用进程在任何时候都能发送数据。
TCP连接的两端都设有发送缓存接收缓存,用来临时存放双向通信的数据。

发送时,应用程序把数据传输给 TCP的缓存后,就可以做自己的事,而TCP在合适的时候把数据发送出去。
接收时,TCP把收到的数据放入缓存,上层的应用进程在合适的时候读取缓存中的数据。

面向字节流
(Byte Stream)
TCP中的指的是流入到进程或从进程流出的字节序列

2.TCP段格式

  • 源端口:16比特(2字节),写入源端口号,用来标识 发送该TCP报文段的应用进程
  • 目的端口:16比特(2字节),写入目的端口号,用来标识 接收该TCP报文段的应用进程
  • 顺序号:32比特(4字节),取值范围[0,232-1],指出本TCP报文段数据载荷的第一个字节的序号
  • 确认号:32比特(4字节),取值范围[0,232-1],指出 期望收到对方下一个TCP报文段的数据载荷部分的第一个字节的序号,同时也是对之前收到的所有数据的确认。
  • 数据偏移:4比特,该值的单位是4字节。用来指出TCP报文段的首部长度
    • 首部固定长度20字节 所以数据偏移字段的最小值为(0101)
    • 首部最长长度60字节 所以数据偏移字段的最大值为(1111)(TCP段: 20字节的头部+最多40字节可选部分+用户数据)
  • URG:紧急标志位,用来实现紧急操作
  • ACK:确认标志位
  • PSH:推送标志位,用来实现推送操作
  • RST:复位标志位,用来复位TCP连接
  • SYN:同步标志位,在TCP连接建立时用来同步序号,表示这是一个连接请求或连接接受报文
  • FIN:终止标志位,用来释放TCP连接
  • 窗口:16比特,该值的单位为 字节。指出发送本报文段的一方的接收窗口
  • 校验和:16比特(2字节),用来检查TCP报文段在传输过程中是否出现了误码
  • 紧急指针:16比特,该值的单位为字节,用来指明紧急数据的长度
  • 选项:增加选项可以增加TCP的功能
  • 填充:由于选项的长度可变,使用填充来确保报文段首部能被4整除

(一)掌握TCP主要字段的作用:顺序号和确认号,窗口大小,SYN/FIN/ACK等。

1.顺序号

(1)字节序号

TCP 连接中,为传送的字节流(数据)中的每一个字节按顺序编号

(2)初始序号 ISN

当新连接建立的时候,第一个字节数据的序号称为 ISN(Initial Sequence Number),即初始序号。ISN 一开始并不一定就是 1。

初始序号是非常非常重要的概念,它告诉对端,第一个报文段是谁!

(3)报文段序号

如果一个 TCP 报文段的序号为 301,它携带了 100 字节的数据,就表示这 100 个字节的数据的字节序号范围是 [301, 400],该报文段携带的第一个字节序号是 301,最后一个字节序号是 400.

注意:序号字段只有在下面两种情况的任意一种才有意义:

  • 数据字段至少包含一个字节
  • 这是一个 SYN 段,或者是 FIN 段,或者是 RST 段。(如:一个SYN将占用一个序号,所以顺序号要加1)

2.确认号

每传送一个 TCP 段,都要等待对方回复一个确认。不过这种方式效率太低,在 TCP 协议中,一般采用累积确认的方式,即每传送多个连续 TCP 段,可以只对最后一个 TCP 段进行确认。

  • 只有当 ACK 标志位被置位的时候,确认号这个字段才有效。

比如发送方发送了一个报文段序号为 301 的 TCP 段,这个段携带了 100 字节数据,则接收方应当回复的确认号是 401(401=301+1,这也很好理解,比如301号携带1个字节,现在确认号为302,期望收到302),它表示接收方已经收到了字节序号为 [0, 400] 的数据,现在期望你发送字节序号为 401 以及以后的数据。

3.窗口大小

“窗口大小”字段通常用于告知对方自己的能够接受的数据量大小。

窗口本质就是一个缓冲区buffer,该字段的值用于告知对方自己剩余的可用缓冲区大小。在每一个TCP报文段中都会通过“窗口”字段告知对方自己的所能接收数据的大小。窗口大小通常用滑动窗口流量控制。

4.SYN

用于建立连接过程,在连接请求中,SYN=1和ACK=0表示该数据段没有使用捎带的确认域,而连接应答捎带一个确认,即SYN=1和ACK=1。注:捎带是指对客户机到服务器数据的确认被装载在一个承载服务器到客户机的数据

一个SYN将占用一个序号,所以要顺序号会加1。(建立连接过程中)

5.FIN

用于释放一个连接,表示发送方已经没有数据要传输了。此时,接收方可能继续接收数据,好在SYN和FIN数据段都有序列号,从而保证了这两种数据段以正确顺序被处理

6.ACK

当ACK=0时,表示该数据段不包含确认信息,当ACK=1时,表示该报文段包括一个对已被成功接收报文段的确认。

(二)掌握TCP的基本特性,提供面向字节流的双向可靠数据传输服务

  1. TCP是面向连接的传输层控制协议
  2. 每一条TCP连接只能有两个端点,是点对点连接
  3. TCP提供全双工通信,连接的两端都可以临时存放双向通信的数据
  4. TCP提供可靠交付的服务,传送的数据保证无差错、不丢失、不重复、并且按序到达
  5. TCP面向字节流,将应用程序交下来的数据仅看成是一串无结构的字节流,写入缓存后根据对方的窗口值和当前网络拥塞的程度来决定一个报文段应该包含多少个字节。

(三)掌握MTU、MSS的概念

MSS:maximum segment size,最大分节大小,为TCP数据包每次传输的最大数据分段大小,一般由发送端向对端TCP通知对端在每个分节中能发送的最大TCP数据。MSS值为MTU值减去IPv4 Header(20 Byte)和TCP header(20 Byte)得到。

MTU:maximum transmission unit,最大传输单元,由硬件规定,如以太网的MTU为1500字节。

二、连接管理

每一条TCP连接都有两个端点。TCP连接的端点叫做套接字(socket)。根据RFC 793的定义:端口号拼接到(concatenated with)IP地址即构成了套接字。因此,套接字的表示方法为:

套接字 socket = (IP地址:端口号)

例如,若IP地址是 192.168.1.112,而端口号是 80,那么得到的套接字就是(192.168.1.112: 80)。

每一条TCP连接唯一地被通信两端的两个端点(即两个套接字)所确定。即:

TCP连接 ::= {socket1, socket2} = {(IP1: port1), (IP2: port2)}
IP1 和 IP2 分别是两个端点主机的IP地址,而port1 和 port2 分别是两个端点主机中的端口号。TCP连接的两个套接字就是socket1 和 socket2。

TCP连接的建立和释放是每一次面向连接的通信中必不可少的过程。因此TCP通信过程有3个阶段,即:连接建立、数据传输和连接释放。

(一)掌握三次握手的连接建立过程

TCP连接的建立采用客户-服务器方式。主动发起连接建立的应用进程叫做客户端(client),而被动等待连接建立的应用进程叫做服务器(server)

TCP建立连接的过程叫做握手,握手的过程需要在客户端和服务器之间交换3个TCP报文段,因此我们形象地将TCP连接的建立过程称为“三次握手”。

下图是TCP三次握手建立连接的过程,假定主机A运行的是TCP客户程序,主机B运行的是TCP服务器程序。最初两端的TCP进程都处于关闭(Closed)状态。注意:A客户端主动打开连接,B服务器被动打开连接。

 描述整个过程:

【1. 服务器初始化状态】

主机B的TCP服务器进程先创建传输控制块(TCB),这时socket(),bind() 函数已经执行完毕,服务器进程准备接受客户进程的连接请求。然后服务器进程调用listen()函数,此时服务器进程处于监听(listen)状态,紧接着调用accept()函数,等待客户的连接请求到来。如有,即作出响应。

  • 服务端进程调用函数顺序:socket—>bind—>listen—>accept。当执行到accept()函数时,服务器进程会一直处于阻塞状态,直到有客户连接请求到达才返回。

【2. 客户端发起连接请求,发送SYN同步报文段,第一次握手】

主机A的客户进程也是首先创建传输控制块(TCB),然后向主机B发出连接请求报文段,这时请求报文段的首部的同步位SYN=1,同时选择一个初始序号seq=x,这个初始序号x就是随机产生的整数ISN。TCP规定,SYN报文段(即SYN=1的TCP报文段)不能携带数据,但要消耗一个序号(ack=接收顺序号+接收长度,这里接收长度为1)。这时,TCP客户进程进入 SYN-SENT(同步已发送) 状态。

  • 客户进程调用函数顺序:socket——>connect。当客户进程调用connect()函数时,客户进程就会向服务器进程发出连接请求的SYN同步报文段。

【3. 服务器同意建立连接,回复确认信息,第二次握手】

主机B的服务器进程收到连接请求报文段后,如同意建立连接,则向主机A的客户进程发送确认报文段。在确认报文段的首部中,SYN=1,ACK=1,确认号=x+1(没有数据,所以长度为0,直接seq+1即可),同时也为自己选择一个初始序号seq = y。请注意,这个确认报文段也不能携带数据,但同样要消耗一个序号。这时,TCP服务器进程进入 SYN-RCVD(同步收到) 状态。

【4. 客户端确认连接,发送确认连接信息,第三次握手】

主机A的客户进程收到主机B的服务器进程的确认报文段后,还要向主机B的服务器进程的SYN报文段给出确认。在确认报文段的首部中,ACK=1,确认号ack=y+1,而自己的序号seq=x+1。TCP的标准规定,ACK报文段可以携带数据。但如果不携带数据,则不消耗序号。在这种情况下,客户进程的下一个数据报文段的序号仍是seq=x+1。这是,TCP连接已经建立,主机A的客户进程也进入 ESTABLISHED(已建立连接)状态。当主机B的服务器进程接收到主机A的客户进程发来的确认报文段后,也进入ESTABLISHED(已建立连接)状态。

  • 上面给出的TCP连接建立过程叫做“三次握手”。请注意,在上图中,B发送给A的报文段,也可以拆成两个报文段分两次发送。即先发送对A的连接请求同步报文段的确认报文段(ACK=1, ack=x=1),接着再发送B自己的连接请求的同步报文段(SYN=1, seq=y)给A。A收到B的同步报文段后,再给B回复一个确认报文段。那么,这样的过程就变成了“四次握手”,但效果是一样的。

(二)了解连接释放过程,掌握什么是TIME-WAIT状态

1.TCP连接的释放

TCP连接的释放可以用“四次挥手”的过程来描述。数据传输结束后,通信的双方都可释放连接。现在 客户端A和服务器B都处于 ESTABLISHED 状态。释放连接的过程如下图所示:

 描述整个过程:

【1. A客户端主动断开连接,发送释放连接的FIN报文段,第一次挥手】

A客户端进程先向B服务器进程发送释放连接的FIN结束报文段,并停止再发送数据,主动关闭TCP连接。在结束报文段的首部中,终止控制位FIN=1,其序号字段seq=u,它等于前面已发送过的数据的最后一个字节的序号加1。此时,A客户端进程进入 FIN-WAIT-1(终止等待1)状态,等待B服务器进程的确认。请注意,TCP规定,FIN报文段即使不携带数据,它也要消耗掉一个序号。这点和SYN报文段是一样的。

【2. B服务器收到A客户端的结束报文段,发出确认报文段,第二次挥手】

B服务器进程收到A客户端进程发来的释放连接的FIN结束报文段后,立即发出确认报文段,确认号ack=u+1,而这个报文段自己的序号seq=v,等于B服务器前面已发送过的数据的最后一个字节的序号加1。然后B服务器进程进入 CLOSE-WAIT(关闭等待)状态。TCP服务器进程这时通知高层的应用进程,那么从 A 到 B 这个方向的连接就释放了,此时TCP连接处于半关闭(half-close)状态,即A客户端已经没有数据要发送了,但B服务器若发送数据,A客户端仍要接收。也就是说,从 B 到 A 这个方向的连接并未关闭,这个状态可能会持续一段时间。
A客户端收到B服务器的确认报文段后,就进入 FIN-WAIT-2(终止等待2)状态,等待B服务器发出的FIN结束报文段。

【3. B服务器释放连接,发出连接释放的结束报文段,第三次挥手】

当B服务器已经没有要向A客户端发送的数据时,其应用进程就通知TCP释放连接,向A客户端发送释放连接的结束报文段。在这个结束报文段的首部中,终止控制位FIN置1,假定其序号字段为w(在半关闭状态中,B服务器可能又发送了一些数据),同时还必须重复上次已发送过的确认号ack=u+1。这时,B服务器进程就进入 LAST-ACK(最后确认)状态,等待A客户端的确认。

【4. A客户端收到B服务器释放连接的结束报文段,发出确认报文段,第四次挥手】

A客户端在收到B服务器的释放连接的结束报文段后,必须对此发出确认,即向B服务端发送一个确认报文段。在确认报文段的首部中,控制位ACK=1,确认号字段ack=w+1,而自己的序号字段seq=u+1(根据TCP标准,前面发送过的FIN报文段是要消耗一个序号的,也即是ack=接收顺序号+接收长度,这里长度为FIN为1)。然后A客户端进入到TIME-WAIT(时间等待)状态

请注意,此时TCP连接还没有释放掉,必须经过时间等待计时器(TIME-WAIT timer)设置的时间2MSL后,A才进入到 CLOSED 状态。时间MSL(Maximum Segment Lifetime,最长报文段寿命) 即一个TCP报文段存活的最长时间。RFC793建议设为2分钟,现在可以根据情况使用更小的MSL值。因此从A客户端进入到 TIME-WAIT 状态后,要经过4分钟才能进入到CLOSED状态,才可以建立下一个新的连接,当A客户端撤销相应的传输控制块TCB后,就结束了这次的TCP连接。

B服务器只要收到了A客户端发出的确认报文段,就进入 CLOSED状态。同样,B服务器在撤销相应的传输控制块TCB后,就结束了此次的TCP连接。

可以发现,B服务器结束TCP连接的时间要比A客户端早一些。

上述内容就是TCP连接释放的过程,俗称“四次挥手”过程,其实质上是四报文挥手。

2.TIME-WAIT

(1)为什么客户端在 TIME-WAIT 状态时,必须等待2MSL的时间才能进入到 CLOSED状态呢?

第一,为了保证客户端发送的最后一个ACK报文段能够到达对端,即保证可靠地终止TCP连接。因为如果出现网络拥塞,这个ACK报文段是有可能丢失的,因而使处于LAST-ACK状态的服务器收不到客户端对自己已发送过的FIN+ACK报文段的确认。那么,服务器会超时重传这个FIN+ACK报文段,而客户端就能在2MSL时间内收到这个重传的FIN+ACK报文段。接着客户端重传一次确认,重新启动2MSL计时器。最后,客户端和服务器都正常进入到CLOSED状态。如果客户端在 TIME-WAIT 状态时不等待一个2MSL时间,而是在发送完ACK确认报文段后立即释放连接,进入到CLOSED状态,那么就无法收到服务器重传的FIN+ACK报文段,因而也不会再发送一次确认报文段。这样,服务器就无法按照正常步骤进入到CLOSED状态。

第二,防止已失效的连接请求报文段出现在本次TCP连接中。客户端在发送完最后一个ACK报文段后,再经过2MSL的时间后,就可以使本次TCP连接持续的时间内所产生的所有报文段都从网络上消失。这样就可以使下一个新的TCP连接中不会出现之前旧的连接请求报文段。( 最坏需要等待2*MSL,确保不会有FIN Y到来,对新连接造成干扰)

(2)为什么是2MSL,这个时间是如何得来的?

我们知道,MSL是TCP报文段的最大生存时间,2MSL的时间是从客户端发出最后一个ACK报文段开始计时的,考虑到了重传的因素。

客户端—[ACK报文段]—>服务器            1MSL

服务器—[FIN+ACK报文段]—>客户端    1MSL (如果服务器在超时时间内没有收到客户端的ACK报文段,就重传FIN+ACK报文段)

保证在TCP的两个传输方向上,那些尚未被接收或迟到的报文段都消失,理论上保证最后一个ACK报文段可靠到达。

三、TCP流量控制:可变窗口的滑动窗口协议,掌握收到DATA和ACK之后窗口的变化情况

1.TCP流量控制

一般来说,我们总是希望数据传输能尽可能快一点。但如果发送方把数据发送得过快的话,接收方就可能来不及接收,这就会造成数据的丢失。而TCP的流量控制机制就是为了解决这个端到端的数据传输速率问题。

所谓流量控制就是根据接收方的实际接收能力,来控制发送方的数据发送速率。从而让发送方的发送速率不要太快,要让接收方来得及接收。

流量控制解决的是一个端到端的问题,是接收端控制发送端发送数据的速率,以便使接收端来得及接收。

TCP协议使用滑动窗口机制来实现对发送方的流量控制。

2.可变窗口的滑动窗口协议

利用滑动窗口可以提高传输速度

我们知道,TCP是以报文段为单位发送数据的,如果每发一个段就进行一次确认应答处理的话,这样的传输方式有一个缺点。那就是,包的往返时间越长通信性能就越低。为了解决这个问题,TCP引入了窗口这个概念。即使在往返时间较长的情况下,它也能控制TCP网络通信性能的下降。

发送方发送数据时不再是一次只发送一个TCP报文段,而是一次连续发送多个报文段。也就是说,发送方在发送了一个段之后不必一直等待这个段的确认应答,而是继续发送下一个报文段。每当收到一个报文段的确认应答后,窗口就向前滑动一个报文段的长度,因为已发送并收到确认应答的报文段不需要再保留在窗口中了,但已发送还未收到确认应答的段还必须保留在窗口中,以便在超时重传时使用。需要注意的是,滑动窗口是以字节为单位向前滑动的

示例:假设一个TCP报文段包含有1000字节的数据(注意:不包含TCP首部长度),发送端一次发送4个报文段。如下图所示:

说明:滑动窗口的大小是4个报文段的数据部分长度,即4000字节。这里的窗口大小就是指无需等待确认应答而可以继续发送数据的最大值。

当主机A收到第1个报文段的确认应答后(收到主机B发来的确认号1001),即序号 1 ~ 1000 的数据已被确认,此时滑动窗口就可以向前移动1000字节的长度,此时窗口的左边界序号是1001,右边界序号是5001。右边界 - 左边界 = 窗口大小。

当主机A收到第2个报文段的确认应答后(收到主机B发来的确认号2001),即序号 1001 ~ 2000 的数据已被确认,此时滑动窗口继续向前移动1000字节的长度,此时窗口的左边界序号是2001,右边界序号是6001。

分析:窗口以外的部分中,窗口左边部分表示已发送且已收到确认应答。这些数据显然不需要再保留了。窗口右边部分表示不允许发送的数据。因为接收方都没有为这部分数据保留临时存放的缓存空间。

可以发现,发送窗口的位置由窗口左边界和右边界共同确定。发送窗口左边界每次都是滑动到收到确认应答号的位置上,而发送窗口右边界则是不允许发送数据的第1个字节序号

这种可以顺序地将多个报文段同时发送以提高TCP通信性能的机制,被称为滑动窗口机制。

3.收到DATA和ACK之后窗口的变化情况

发送窗口与接收窗口

上面所讲的内容是从发送方的角度来解释滑动窗口机制的。发送方的窗口称为发送窗口,而接收方也有一个窗口,称为接收窗口。

发送窗口,表示的是发送方一次可以连续发送出去的数据量,以字节为单位。凡是已经发送过的数据,在未收到确认之前都必须暂时保留在发送窗口中,以便在超时重传时使用。发送窗口内的数据都是尚未收到确认应答的。

接收窗口,表示的是接收方一次能够连续接收的数据量,以字节为单位。接收窗口内的数据都是允许被接收的。

需要注意的是,发送窗口值不是由发送方自己决定的,而是根据接收方给出的窗口值,发送方再构造出自己的发送窗口值

  • 在TCP报文段的首部结构中,有一个“窗口”字段,其作用是告诉对方本端的接收窗口的大小,以便控制发送方的发送窗口大小。
  • 二者的关系:发送窗口值 ≤ 接收窗口值
  • 此外,发送方的发送窗口大小还要受到当前网络拥塞程度的制约。我们暂时不考虑网络拥塞的影响,后续讲述TCP拥塞控制时再讨论。

为了便于下面的解释说明,我们假定一个TCP报文段的数据部分长度为1字节,数据传输方向为:A(发送方) —> B(接收方)

假定发送方A的发送窗口大小为20字节,接收方B的接收窗口也为20字节。

现在假定A发送了序号为 31~41 的数据。这时,发送窗口位置并未改变,但发送窗口内靠后面的有11字节(黑色小方框表示)表示已发送但未收到确认。而发送窗口内靠前面的9个字节(42~50)是允许发送但尚未发送的。如下图所示:

从上图可以看出,要描述一个发送窗口的状态需要三个指针:P1,P2 和 P3。指针都指向字节的序号。这三个指针指向的几个部分的意义如下:

  • P3 - P1 = A的发送窗口
  • P2 - P1 = 已发送但尚未收到确认的字节数
  • P3 - P2 = 允许发送但目前尚未发送的字节数(又称为可用窗口或有效窗口)

同时,可以看到,发送方的包可以分为四种状态:

  • 已发送并收到确认的包
  • 已发送但尚未收到确认的包
  • 允许发送但尚未发送的包
  • 不允许被发送的包
  • <说明> 这里的包指的是TCP报文段,因为TCP是以报文段为单位发送数据的。

再来看看接收方B的接收窗口。B 的接收窗口大小为20字节。在接收窗口以外的部分,到序号30为止的数据都是已经发送过确认,并且已经交付上层应用了。因此在 B 的接收窗口中可以不用再保留这些数据。接收窗口内的数据(31~50)是允许接收的。在上图中,B 收到了序号为 32 和 33 的数据。这些数据没有按序到达,因为序号为 31 的数据没有收到(也许丢失了,也许滞留在网络中的某处)。请注意,接收方 B 只能对按序收到的数据中的最高序号给出确认应答,因此 B 发送的确认报文段中的确认号仍为 31(即期望下一次收到的序号),而不能是 32 或是 33,更不能是34。

现在假定 B 收到了序号为31的数据,并把序号为 31~33的数据交付主机,然后B从接收缓存中删除这些数据。接着把接收窗口向前移动3个序号的长度,同时给A发送确认,其中B的接收窗口值仍为20,但确认号为34。这表明 B 已经收到了序号 33 为止的数据。我们注意到,B 还收到了序号为37,38 和 40 的数据,但这些都没有按序到达,只能先暂存在接收窗口中。A收到B的确认后,就可以把发送窗口向前滑动3个序号的长度,但指针P2不动。可以看出,现在A的可用窗口增大了,可发送的序号范围是 42~53,即12个序号的长度,之前是9个序号的长度。

如下图所示:

A 在继续发送 42 ~ 53 的数据后,指针P2向前移动和指针P3重合,意味着此时可用窗口大小为0。发送窗口内的序号都已用完,但还没有收到确认(如下图所示)。由于A的发送窗口已满,可用窗口已减小到零,因此必须停止发送数据。请注意,存在下面这种可能性:

  • 发送窗口内所有的数据都已正确达到B,B 也早已发出了确认。但不幸的是,所有这些确认都滞留在网络中了。在没有收到B的确认时,A 不能猜测:“获取 B 收到了吧”。为了保证可靠传输,A 只能认为 B 还没有收到这些数据。于是,A 在经过一段时间后(由超时计时器控制)就重传发送窗口中的这部分数据(34 ~ 53),重新设置超时计时器,直到收到B的确认为止。如果 A 收到的确认号落在了发送窗口内,那么A就可以使发送窗口继续向前滑动,并发送新的数据。此时,指针P1指向的位置就是A收到的确认号的位置。

滑动窗口总结

  1. TCP首部中的窗口字段指出了现在运行对方发送的数据量。窗口值是经常动态变化者的。
  2. TCP 使用滑动窗口机制。发送窗口里面的序号表示允许发送的序号。发送窗口左边的部分表示已发送且已收到了确认应答,而发送窗口右边的部分表示不允许发送。发送窗口右边界的变化有两种情况:一是不动(没有收到新的确认应答);二是前移(收到了新的确认应答)。发送窗口通常是不断向前移动的。

四、TCP拥塞控制

在计算机网络中的链路容量(即带宽)、交换结点中的缓存和处理机等,都是网络的资源。在某段时间,如果对网络中的某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要发生变化,这种情况就叫做拥塞(congestion)

拥塞控制的概念:所谓拥塞控制就是防止过多的数据注入到网络中,这样就可以使网络中的路由器或链路不至于过载。

拥塞控制的前提条件:网络能够承受现有的网络负荷。

拥塞控制与流量控制的区别:

  • 拥塞控制是一个全局性的过程,涉及到所有的主机、路由器,以及与降低网络传输性能有关的所有因素。
  • 流量控制往往是指点对点通信量的控制,是个端到端的问题(接收端控制发送端)。流量控制所要做的就是抑制发送端发送数据的速率,以便使接收端来得及接收。

流量控制和拥塞控制实例

  • 设某个光纤网络的链路传输速率为 1000 Gbit/s。有一台巨型计算机向一台个人电脑以 1 Gbit/s的速率传送文件。显然,网络本身的带宽是足够大的,因而不存在产生拥塞的问题。但流量控制却是必须的,因为巨型计算机必须经常停下来,以便使个人电脑来得及接收。(流量控制
  • 如果有另一个网络,其链路传输速率为 1 Mbit/s,而有1000台大型计算机连接在这个网络上,假定其中的 500 台计算机分别向其余的 500 台计算机以100 kbit/s的速率发送文件。那么现在的问题已不是接收端的大型计算机是否来得及接收,而是整个网络的输入负载是否超过网络所能承受的。(拥塞控制

TCP 进行拥塞控制的过程有四个部分,分别是:慢开始(slow-start)、拥塞避免(congestion avoidance)、快重传(fast retransmit) 和 快恢复(fast recovery)

下面介绍这些算法的原理。为了集中精力讨论拥塞控制,我们假定:

  1. 数据是单方向传送,对方只传送确认报文段。
  2. 接收方总是有足够大的缓存空间,因而发送窗口的大小由网络的拥塞程度来决定。
  3. 以TCP报文段的个数为讨论问题的单位,而不是以字节为单位。

(一)掌握慢启动、拥塞避免、快速重传和快速恢复

1.拥塞窗口(cwnd)

 TCP 的拥塞控制也叫做基于窗口的拥塞控制。为此,发送方维持了叫做拥塞窗口 cwnd(congestion window)的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地变化。发送方让自己的发送窗口等于拥塞窗口

发送方控制拥塞窗口cwnd的原则是:只有网络没有出现拥塞,拥塞窗口就可以再增大一些,以便把更多的分组发送出去,这样就可以提供网络的利用率。但只要网络出现拥塞或者用可能出现拥塞,就必须把拥塞窗口减小一些,以减少注入到网络中的分组数,以便缓解网络出现的拥塞。

当网络发生拥塞时,路由器就要丢弃分组。因此,只要发送方没有按时收到应当到达的确认报文,也就是说,只要出现了超时,就可以猜测网络可能出现了拥塞。现在通信线路的质量一般都很好,因传输出差错而丢弃分组的概率很小(远小于1%)。因此,判断网络拥塞的依据就是出现了超时

2.慢开始

慢开始算法的思路是这样的:当主机开始发送数据时,由于不清楚网络的负荷情况,所以如果立即把大量数据字节注入到网络,那么就有可能引起网络拥塞。经验证明,较好的方法是先探测一下,即由小大到逐渐增大发送窗口,也就是说,由小到大逐渐增大拥塞窗口数值。

初始拥塞窗口cwnd=初始窗口IW

  • 最初初始窗口IW为1个MSS
  • RFC 6928建议: 初始窗口提高到最多10个MSS(具体多少个根据MSS 的大小选择)

连接建立后,每收到一个新的ACK,拥塞窗口增加1个MSS

  • 每个RTT之后,拥塞窗口翻倍

引入慢启动阈值ssthresh=超时时拥塞窗口的一半

  1. 拥塞窗口小于ssthresh,则为慢启动阶段,拥塞窗口指数增加
  2. 拥塞窗口大于(等于) ssthresh,则为拥塞避免阶段,拥塞窗口线性增加
  3. 拥塞窗口=ssthresh,标准中可采用慢启动也可拥塞避免,实践中一般采用拥塞避免

3.拥塞控制

 拥塞避免算法的思路是让拥塞窗口 cwnd 缓慢地增长,即每经过一个往返时间 RTT 就把发送方的 拥塞窗口 cwnd 加 1,而不是像慢开始阶段那样加倍增长。

  • 有时,个别报文段会在网络中丢失,但实际上网络并未发生拥塞。如果发送方迟迟收不到确认,就会产生超时,就会误认为网络发生了拥塞。这就导致发送方错误地启动慢开始,把拥塞窗口 cwnd 又置为1,因而降低了传输效率。
  • 为了解决这个问题,需要用到快重传算法。采用快重传算法的目的是:可以让发送方尽早知道发生了个别报文段的丢失。

动态调整拥塞窗口:超时和重开空闲连接

如果RTO计时器超时,意味着严重拥塞

  • 慢启动阈值ssthresh设置为当前拥塞窗口的一半
  • cwnd设置为丢失窗口(Loss Window),LW为1个MSS

如果TCP空闲超过一段时间(重传超时的时间),在重新开始传输数据时,进入慢启动过程

  • 慢启动阈值ssthresh设置为当前拥塞窗口的一半
  • 拥塞窗口cwnd设置为重启窗口(restart window),一般为IW 

4.快速重传

TCP发送方收到3个重复ACK(即共收到同一报文段的4个ACK):随后的 TCP段己丢失的可能性就很大,立即重传该丢失的TCP段,进入慢启动 阶段,在新的ACK回来或超时前忽略后续的重复ACK(不进行快速恢复)

TCP 认为这种情况不严重,因为大部分没丢,只丢了一小部分,则 ssthresh 和 cwnd 变化如下:

  • cwnd = cwnd/2 ,也就是设置为原来的一半;
  • ssthresh = cwnd;
  • 进入快速恢复算法

5.快速恢复

进入快速恢复之前,cwnd 和 ssthresh 已被更新了:

  • cwnd = cwnd/2 ,也就是设置为原来的一半;
  • ssthresh = cwnd;

然后,进入快速恢复算法如下:

ndup记录最近收到的重复ACK的个数)

  1. 当收到第三个重复ACK( 即ndup == 3)时:
    • 快速重传丢失的TCP段
    • 设置ssthresh = max(cwnd/2, 2*SMSS)
    • 设置cwnd = ssthresh + ndup*MSS(已经离开网络并且被缓存)
  2. 每次收到更多的重复ACK(对同一TCP段)时,更新ndup
    • 拥塞窗口加1:cwnd += MSS;
    • cwnd = ssthresh + ndup* MSS
    • 如果cwnd允许,传输新的分组
  3. 当确认新数据下一个ACK(即丢失报文段及其后各报文段的累加确认)到达时:
    1. 设置cwnd = ssthresh
    2. 进入拥塞避免阶段

也就是没有像「超时重传」一夜回到解放前,而是还在比较高的值,后续呈线性增长。

  • 如果期间RTO超时,慢启动: ssthresh = cwnd/2; cwnd = MSS(认为超时重传情况严重)

(二)掌握TCP吞吐率模型的分析方法

  1. 每次拥塞窗口达到W时,1个(携带MSS数据)分组丢失
  2. 拥塞窗口减少到W/2分组,然后线性增加
    • 每个RTT,拥塞窗口增加一个分组
    • 下次丢失前拥塞窗口从W/2-> W

每个周期:

  • 时间:W/2个RTT
  • 在一个周期时间(W/2个RTT)中传输的分组个数 = W/2 + W/2+1 + …+W = 3W2/8

每个周期传输分组数3W2/8,其中有1个丢失

分组丢失率p

则平均吞吐率BW为:

五、TCP计时器

TCP协议是面向连接、提供可靠交付的服务的传输层协议。 为了保证传输的可靠性,TCP 使用了多种定时器。

  • MSL(Maximum Segment Lifetime,最长报文段寿命)
  • RTT(往返时间):采样值,一般实时计算,比较严格。
  • TTL(IP数据报生存时间):固定值,在IP首部的 “生存时间” 字段中设置。
  • MSL(TCP报文段的最大生存时间):固定值,MSL >= TTL。

(一)掌握重传计时器:要考虑哪些方面的要素:基于RTT和标准偏差的估计,重传TCP段的超时如何处理?

1.重传计时器

发送方每发送完一个TCP报文段,就启动超时计时器。如果在超时计时器到期之前收到了对方的确认,就撤销已设置的计时器;如果超时计时器到期后仍未收到对方的确认,就认为刚才发送的报文段丢失了,因而重传前面发送过的报文段。

超时重传时间的选择:设置RTO(Retransmission Time-Out)值。RTO 不是固定值,需要参考测量所得的往返时间RTT(Round Trip Time)的样本值。

超时重传时间 RTO 的值应该略大于报文往返 RTT 的值

2.基于RTT和标准偏差的估计

第一次采样到来时

  • EstimateRTT = SampleRTT
  • Deviation = SampleRTT/2

后续采样:

  • EstimatedRTT = (1 - α) x EstimatedRTT + α x SampleRTT     α=1/8
  • Deviation = (1 - β) x Deviation + β x | SampleRTT - EstimatedRTT |       β=1/4   α、β就是本次的占比

超时计算:

  • 超时重传时间 RTO=Timeout = EstimatedRTT + 4 x Deviation

除了第一次,每次EstimatedRTT、Deviation 、RTO依次计算

只对的携带了用户数据的TCP段进行采样 • 重传TCP段的超时设置为上次超时的一倍

3.重传TCP段的超时如何处理

如果TCP段超时重传时怎么办

问题:对重传段的RTT测量有歧义  • 收到的有可能是重传段的ACK  • 收到的有可能是原TCP段的ACK

Karn方法

  1. 对重传的分组不测量RTT,不更新RTT估计
  2. 重传分组的超时设置采用指数后退算法:原超时的2倍

六、特殊环境下的TCP:了解在高速网络环境(长肥网络Long Fat Networks)下最初的TCP协议有哪些问题。

1.长肥网络LFN(Long Fat Networks)

RTT * Bandwidth

  • 管道的容量,TCP发送者最多允许发送的尚未确认的数据大小
  • 如果其远远超过105 比特或12500字节,则称为长肥网络LFN

如果一个包含序号 N字节数据的报文段在网络上被迟延并在连接仍然有效时又出现,会发生什么情况呢?这仅仅是一个相同序号N在MSL期间是否被重用的问题,也就是说,网络是否足够快以至于在不到一个MSL的时候序号就发生了回绕。

2.高速网络环境下最初的TCP协议有哪些问题

顺序号回绕:一个顺序号使用了,如果接下来传输了232 个字节的数据,则该顺序号又被再次使用

顺序号回绕时,确保前一个顺序号已经不会出现在网络中了,即要求 顺序号回绕时间 > MSL(Maximum Segment LifetimeTCP报文段的最大生存时间)

时间戳选项TSOPT用于解决数据速率过快带来的顺序号回绕

七、了解UDP协议的特性。了解检验和字段为可选的。

1.UDP

UDP在IP层上附加了简单的多路复用功能,即允许多个应用程序通过socket接口将数据从源端主机发送给目的端主机
UDP是一种无连接方式的、不可靠的运输协议

2.检验和字段

UDP的校验和是可选的,当校验和字段为0时,表明该UDP报文未使用校验和,接收方就不需要校验和检查了!那如果UDP校验和的计算结果是0时怎么办呢?“如果校验和的计算结果为0,则存入的值为全1(65535),这在二进制反码计算中是等效的。”

posted @ 2022-12-24 16:39  ImreW  阅读(97)  评论(0编辑  收藏  举报