Chapter5 - 传输层

本章重要概念:

  1. 运输层为相互通信的应用进程提供逻辑通信。
  2. 端口和套接字的意义。
  3. 无连接的 UDP 的特点。
  4. 面向连接的 TCP 的特点。
  5. 在不可靠的网络上实现可靠传输的工作原理,停止等待协议和 ARQ 协议。
  6. TCP 的滑动窗口、流量控制、拥塞控制和连接管理。

[TOC]

5.1 传输层协议概述

一、进程之间的通信

  • 传输层(Transport layer)又称为运输层
    • 传输层向它上面的应用层提供通信服务,属于面向通信部分的最高层,同时也是用户功能中的最低层。
    • 当两台主机进行端到端通信时,只有主机的协议栈才有运输层,而路由器在转发分组时都只用到下三层的功能。
    • 实现可靠传输:差错控制、顺序控制、拥塞控制
  • 传输层 vs. 网络层
    • 网络层为主机之间提供逻辑通信。
    • 运输层为应用进程之间提供端到端的逻辑通信。
      • 通信的真正端点并不是主机而是主机中的进程
      • 复用:指在发送方不同的应用进程都可以使用同一个运输层协议传送数据。
      • 分用:指接收方的运输层在剥去报文的首部后能够把这些数据正确交付目的应用进程。

】LAN1上的主机A要与LAN2上的主机B进行通信:

考研题

二、传输层的两个主要协议

  • TCP/IP 传输层的两个主要协议都是互联网的正式标准:

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

    • OSI术语称为TPDU(Transport Protocol Data Unit)
    • TCP/IP体系称为TCP报文段(segment)或UDP用户数据报
  • TCP协议

    • 可靠传输协议
    • 提供面向连接的服务
    • 传送数据前要先建立连接,传送结束后释放连接
    • 需进行确认、流量控制、计时器、连接管理等,处理开销较大
    • 基于TCP的典型应用协议:HTTPFTP、…
  • UDP协议

    • 不可靠传输协议
    • 传送数据时无需建立连接
    • 与TCP相比,效率更高,但可能出现数据错、丢包、顺序错等问题
    • 基于UDP的典型应用协议:DNS、RIP、…
  • 下表给出了一些应用和应用层协议主要使用的运输层协议(UDP或TCP)。

三、传输层的端口

  • 传输层需为多个应用进程提供服务 → 复用与分用

    • 复用:应用层所有的应用进程都可以通过运输层再传导IP层(网络层)。
    • 分用:指运输成从IP层收到发送给各应用进程的数据后,必须分别交付指明的各应用进程。
  • 传输层必须提供区分上层应用进程的手段:端口(port)

    • 注意
      • 此端口为软件端口,不同于计算机中的硬件I/O端口和交换机/路由器上的物理端口。
      • 端口号只具有本地意义,为了标志本计算机应用层中各个进程在和运输层交互时的层间接口
  • TCP/IP协议使用16位整数作为端口号

  • 源端口号、目的端口号

  • 端口号分类

    1. 熟知(well-known)端口号或系统端口号:数值一般为 0~1023
      • 例如:HTTP服务使用80,FTP服务使用21,…

    1. 登记端口号:数值为1024~49151
      • 供没有熟知端口号的应用程序使用
      • 须在 IANA 登记,以防重复
    2. 客户端口号或短暂端口号:数值为49152~65535
      • 客户进程临时使用

5.2 用户数据报协议 UDP

一、UDP 概述

  • UDP 只在 IP 的数据报服务之上增加了很少一点的功能:复用、分用、端口和差错检测
  • UDP 为不可靠传输协议,但具有自身特点,与TCP分别面对不同的应用
  • UDP协议的特点
    1. 无连接,即发送数据之前不需要建立连接
    2. 使用尽最大努力交付,即不保证可靠交付,同时也不使用拥塞控制
    3. 是面向报文的。没有拥塞控制,很适合多媒体通信的要求
    4. 支持一对一、一对多、多对一和多对多的交互通信
    5. 首部开销小,只有 8 个字节

二、UDP 首部格式

  • UDP数据报包括2个字段:首部和数据字段。

    • 首部共4个字段,8字节,每个字段的长度都是两个字节
  • 首部各字段的意义

    1. 源端口: 源端口号。
      • 在需要对方回信时选用,不需要时可全用0。
    2. 目的端口: 目的端口号
      • 在终点交付报文时必须使用。
    3. 长度: UDP数据报长度
      • 最小值是8,即仅有首部。
    4. 校验和: UDP数据报的校验和
      • 差错检验。
    • 伪首部(pseudoheader):仅在计算校验和时使用,不实际传输

当运输层从 IP 层收到 UDP 数据报时,就根据首部中的目的端口,把 UDP 数据报通过相应的端口,上交最后的终点 ———— 应用进程。

如果接收方 UDP 在目的端口号上没有应用进程接收数据,则向源主机返回ICMP的“目的不可达”报文。

三、UDP 校验和计算

  • 与IP包头校验和计算类似,不同的是:IP只计算包头校验和,UDP计算整个数据报的校验和。
  • 在发送方:
    • 首先把全零放入检验和字段,再把伪首部以及 UDP 用户数据报看成是由许多16位的字串接起来的。
    • 若 UDP 用户数据报的数据部分不是偶数个字节,则要填入一个全零字节(但此字节不发送)。
    • 然后按二进制反码计算出这些 16 位字的和,将该和写入检验和字段后,就发送这样的 UDP 数据报。
  • 在接收方:
    • 把收到的UDP数据报连通伪首部(以及可能的填充全零字节)一起,按二进制反码求出这些16位字的和。
    • 当无差错时,结果应为全1.

5.3 传输控制协议 TCP 概述

一、TCP的主要特点

  1. TCP 是面向连接的传输层协议
    • 传输数据前必须先建立连接,数据传输完毕后要释放连接
  2. 每一条 TCP 连接只能有两个**端点(endpoint)**,每一条 TCP 连接只能是点对点的(一对一)
  3. TCP 提供可靠交付的服务
    • 无差错、不丢失、不重复、按序到达
  4. TCP 提供全双工通信
    • 在一个连接上,通信双方可同时向对方传输数据
  5. 面向字节流
    • 认为在TCP连接上传输的是字节流
    • 应用程序以数据块为单位与TCP交互,但TCP将其视为无结构的字节流
    • 结果:发送方应用进程发出的数据块与接收方应用进程收到的数据块可能没有一一对应关系,但数据保证一致

  • 要注意的几点:
    • TCP连接是一条虚连接而不是一条真正的物理连接
    • TCP对应用进程一次把多长的报文发送到TCP的缓存中是不关心的
    • TCP根据对方给出的窗口值和当前网络拥塞的程度来决定一个报文段应包含多少个字节(UDP发送的报文长度是应用进程给出的)
    • 如果应用进程传送到 TCP 缓存的数据库太长,TCP可把太长的数据块划分短一些再传送
    • 如果应用进程一次只发来一个字节,TCP也可等待积累有足够多的字节后再构成报文段发送出去

二、TCP的连接

  • TCP把连接作为最基本的抽象
  • TCP连接的端点不是主机,不是主机的IP地址,不是应用进程,也不是传输层的协议端口,TCP 连接的端点叫做套接字(socket)或插口
  • RFC 793 定义:端口号拼接到(contatenated with) IP 地址即构成了套接字
    • 套接字 socket ::= (IP地址: 端口号)
  • 每一条 TCP 连接唯一地被通信两端的两个端点(即两个套接字)所确定。即:
    • TCP 连接 ::= {socket1, socket2} = {(IP1: port1), (IP2: port2)}

5.4 TCP报文段的首部格式

  • 源端口和目的端口字段:各2字节
  • 序号字段:4字节
    • 在TCP连接中传送的数据流中的每一个字节都有序号
    • 序号字段指本报文段所发送的数据的第一个字节的序号,以字节为单位
  • 确认号字段:4字节,期望收到对方的下一个报文段的数据的第一个字节的序号
    • 例:收到对方的报文段中序号为501,数据长度200字节,则返回报文段确认号=701
    • TCP连接是全双工,通信双方可互相发送数据,因此应答与数据一同发送给对方
  • **数据偏移(首部长度)**:4bit,TCP报文段的数据起始位置的偏移,也就是首部的长度,单位是32位字(4字节)
  • 保留字段:6bit,保留
  • 紧急URG:1bit,为1时,紧急指针字段有效,表明有紧急数据,应尽快传送
  • 确认ACK:1bit,为1时,确认号字段有效;为0时,确认号无效
  • 推送PSH:1bit,为1时,接收方将尽快向应用进程交付此报文段,而不是等到整个缓存填满
  • 复位RST:1bit,为1时,表明TCP连接出现严重差错(如由于主机崩溃),须释放连接后重新建立连接
  • 同步SYN:1bit,为1时,表示这是一个连接请求或连接接受报文
  • 终止FIN: 1bit,为1时,表示要求释放TCP连接
  • 窗口大小:2字节,用来让对方设置发送窗口的依据,单位为字节
  • 检验和:2字节,伪首部+首部+数据的校验和
    • 伪首部(pseudoheader)格式与UDP的伪首部相同

  • 紧急指针:2字节,指出本报文段中紧急数据共有多少个字节(紧急数据放在数据的最前面)
  • 选项:长度可变,最长40字节
    • 最早定义的一种选项:最大报文段长度MSS(Maximum Segment Size),用来告知对方报文段中数据最大长度,双方可使用不同的MSS,缺省MSS=536字节
    • 后续增加的选项:窗口扩大选项 、时间戳选项、选择确认选项
  • 填充字段:为了使整个首部长度是4字节的整数倍

无论是对于考试还是考研,各种报文的格式是不需要背的,题目一般会作为条件给出,但需要我们掌握各个字段的含义及作用。

5.5 TCP可靠传输的实现

一、以字节为单位的滑动窗口

TCP基于滑动窗口协议实现可靠传输和流量控制,滑动窗口以字节为单位

  • 发送窗口
    • 在没有收到对方应答的情况下,可以连续把窗口内的数据发送出去
      • 即:窗口内的序号是允许发送的序号
    • 窗口大小的确定:对方发来的窗口大小、拥塞控制
    • 根据收到对方的TCP报文段头部中“acknowledge number”字段,窗口向前滑动
      • “acknowledge number”字段表示在此序号之前的数据已被正确接收
  • 接收窗口
    • 窗口内的数据是允许接收的
    • 窗口后沿以外是已正确接收并交付上层的数据

举例

  • A收到B的报文段中“window size”=20,“acknowledge number”=31,据此构造出自己的发送窗口。
  • 当对方通知的窗口尺寸变化时,发送窗口前沿可能需要向后收缩,但TCP 标准强烈不赞成这样做。

  • A发送11字节后
    • P3 – P1 = A 的发送窗口(又称为通知窗口)
    • P2 – P1 = 已发送但尚未收到确认的字节数
    • P3 – P2 = 允许发送但尚未发送的字节数(又称为可用窗口)
  • B收到了32和33号数据,但未收到31,应答“确认号”=31。
  • B后来收到了31号数据,将31、32、33号数据上交,窗口后沿前移,应答中“确认号”=34

  • B收到31号数据后,窗口前移3字节,并返回确认号34,假定窗口宽度仍为20
  • A收到确认号34后,窗口前移3字节
  • B收到37、38、40号数据,由于数据未按序收全,不能上交

  • A将发送窗口中未发送的数据全部发送后,发送窗口满,停止发送
  • 如果未收到B返回的应答,A等待超时后将重发部分数据,直到收到应答为止

滑动窗口的软件实现

  • 发送缓存用来暂时存放:
    1. 发送应用进程传送给TCP,但尚未发出的数据
    2. 已发送,但尚未收到确认的数据
  • 接收缓存用来暂时存放:
    1. 按序到达的、但尚未被接收应用进程读取的数据
    2. 未按序到达的数据
  • A的发送窗口并不总是和B的接收窗口一样大
  • TCP要求接收方必须有累积确认的功能,这样可以减小传输开销

二、超时重传时间的选择

  • TCP的可靠传输通过校验和+超时重传实现

    • TCP每发送一个报文段,就对这个报文段设置一次计时器
    • 如果计时器设置的重传时间到,但还没有收到确认,就要重传该报文段
  • 超时时间的设置是一个复杂的问题

    • IP层提供数据报服务,每个数据报所选择的路由都可能有变化
    • 传输层的往返时间变化较大
  • TCP采用一种自适应算法计算超时重传时间:加权平均往返时间RTTS (RTT—Round Trip Time)

    • TCP 保留了RTT的一个加权平均往返时间RTTS(又称为平滑的往返时间)
    • 第一次测量到RTT样本时, RTTS就取为该值
    • 以后每测量到一个新的RTT样本,按下式重新计算:
      • 新的RTTS = ( 1 − α ) × 旧的RTTS + α × 新的RTT样本
      • 其中0<α<1, α越小,RTT值更新越慢, α越大,RTT值更新越快
    • RFC 2988 推荐α=1/8,即 0.125
  • 超时重传时间RTO(Retransmission Time-Out)

    • RTO应略大于RTTS
    • RFC 2988 建议使用下式计算RTO:
      • RTO = RTTS + 4 × RTTD
      • 其中,RTTD是RTT的偏差的加权平均值
    • RFC 2988 建议这样计算 RTTD
      • 第一次测量时,RTTD值取为测量到的RTT样本值的一半
      • 在以后的测量中,使用下式计算加权平均的 RTTD:
        • 新的RTTD = ( 1 − β ) × 旧的RTTD + β ×⏐RTTS −新的RTT样本⏐
        • 其中0<β<1,推荐值是1/4,即 0.25

5.6 TCP的流量控制

一、利用滑动窗口实现流量控制

  • 流量控制(flow control)就是让发送方的发送速率不要太快,使接收方来得及接收。
  • 利用滑动窗口机制可以很方便地在 TCP 连接上实现流量控制
    • TCP连接建立过程中,将自己的接收窗口大小告知对方
    • TCP报头中都携带有窗口大小(Window size )字段,告知对方自己接收窗口的剩余大小(即可接收的字节数)
    • 发送方的发送窗口应不大于对方的接收窗口

TCP 流量控制示例

如下图,设A向B发送数据,每一个报文段为100字节长:

  • 连接建立时,B 告诉 A:“我的接收窗口rwnd = 400(字节)”
    • rwnd 表示 receiver window
  • 注意到,主机B进行了三次流量控制
    • 第一次把窗口减小到 rwnd = 300,第二次又减到 rwnd = 200, 最后减到 rwnd = 0,即不允许发送方再发送数据了。
    • 这种使发送方暂停发送的状态将持续到主机B重新发出一个新的窗口值为止。
  • 还应注意到,主机B向A发送的三个报文段都设置了 ACK = 1,只有在 ACK = 1时确认号字段才有意义。

  • 问题——死锁
    • 现在考虑一种情况。在上图中,如果B的接收缓存又有了一些存储空间,那么B会向A发送 rwnd = 400 的TCP报文,然而这个报文段在传送过程中丢失了
    • 于是,A一直等待收到B发送的非零窗口的通知,而B也一直等待A发送的数据。如果没有其他措施,这种互相等待的死锁局面将一直延续下去。
  • 解决——持续计时器(persistence timer)
    • TCP为每一个连接设有一个持续计时器
    • 只要一方收到对方的零窗口通知,就启动持续计时器
    • 若持续计时器设置的时间到,就发送一个零窗口探测报文段(仅携带1字节的数据),而对方在确认这个探测报文段时给出当前窗口值
      • 若窗口仍然是零,则收到这个报文段的一方就重新设置持续计时器
      • 若窗口不是零,则死锁的僵局就可以打破

二、TCP 的传输效率

  • 前面已经讲过,应用进程把数据传送到TCP的发送缓存后,剩下的发送任务就由TCP来控制了。
  • 可以用不同的机制来控制TCP报文段的发送时机
    • 机制一:缓存数据达到一定量就发送
      • TCP维持一个变量,它等于最大报文段长度MSS
      • 只要缓存中存放的数据达到MSS字节时,就组装成一个TCP报文段发送出去
    • 机制二:应用进程控制
      • 由发送方的应用进程指明要求发送报文段,即**推送(push)**操作
    • 机制三:定时发送
      • 发送方的一个计时器期限到了,这时就把当前已有的缓存数据装入报文段(但长度不能超过 MSS)发送出去

5.7 TCP的拥塞控制

一、拥塞控制的一般原理

  • 拥塞(congestion)的概念

    • 在某段时间,若对网络中某资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏,从而产生拥塞,即拥塞产生的条件:
      • Σ对资源的需求 > 可用资源
    • 网络资源:链路带宽、路由节点缓存及处理能力等
  • 拥塞产生的原因

    • 网络拥塞是由多种原因引起的,通过简单地增加某种资源数量往往并不能消除拥塞
    • 例:某路由器缓存容量太小,造成到达该结点的报文丢失,如果增加缓存容量,可能的结果:
      • 报文可在缓存中排队,但如果路由器处理能力和出口链路带宽未增加,报文排队时间过长,发送主机将超时重发。因此拥塞并没有得到解决。
  • 网络拥塞的表现

    • 网络性能下降,具体表现为网络吞吐率下降、报文传输时延增大、丢包率增加、用户端响应时间变长、…
    • 拥塞常常会趋于恶化,即恶性循环
      • TCP重传机制引起
      • 如:一个路由器由于缓存不足丢弃了部分报文,发送端主机将超时重发,导致网络中被注入更多的报文,从而加剧拥塞
  • 拥塞控制(congestion control)与流量控制

    • 拥塞控制:防止过多的数据注入到网络中,使网络中的路由器或链路不致过载
    • 拥塞控制是一个全局性的过程,而流量控制是点对点通信量的控制,是端到端的问题
  • 开环控制与闭环控制

    • 开环控制
      • 在设计网络时事先将有关发生拥塞的因素考虑周到,力求网络在工作时不产生拥塞。
      • 但一旦整个系统运行起来,就不再中途进行改正了。
    • 闭环控制:基于反馈环路,有以下几种措施:
      • 监测网络系统以便检测到拥塞在何时、何处发生
      • 将拥塞发生的信息传送到可采取行动的地方
      • 调整网络系统的运行以解决出现的问题
  • RFC 2581中定义了四种拥塞控制方法

    1. 慢启动(slow-start),又称为慢开始
    2. 拥塞避免(congestion avoidance)
    3. 快重传(fast retransmit)
    4. 快恢复(fast recovery)

二、拥塞控制方法

1. 慢启动和拥塞避免

慢启动(slow-start)
  • 慢启动进行拥塞控制的基本思路

    • 开始发送时,如果立即把大量数据注入网络,则可能导致拥塞
      • 因为此时不知道网络的负荷状况
    • 较好的方法是:试探性地从小到大逐渐增大发送窗口
  • 拥塞窗口cwnd (congestion window)

    • 发送方维持一个叫做拥塞窗口的状态变量,其大小取决于网络的拥塞程度,并且动态地在变化
    • 发送方让自己的发送窗口等于拥塞窗口,如再考虑到接收方的接收能力,则发送窗口还可能小于拥塞窗口
  • 发送方控制拥塞窗口的原则

    • 只要没有出现拥塞,拥塞窗口就增大一些,以便把更多的分组发送出去
    • 一旦出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数
  • 如何判断是否发生拥塞?

    • 当网络发生拥塞时,路由器将丢弃分组,进而导致发送方无法按时收到确认报文。
    • 因此,判断网络拥塞的依据就是出现了超时
  • 慢启动的工作过程

    • 开始发送报文段时,设置拥塞窗口cwnd = 1,即设置为一个最大报文段MSS的数值
    • 每收到一个对新的报文段的确认后,将拥塞窗口加 1,即增加一个 MSS 的数值
    • 用这样的方法逐步增大发送端的拥塞窗口cwnd,可以使分组注入到网络的速率更加合理
    • 注意:TCP中窗口大小是以字节为单位的。为方便起见,这里以MSS为单位讨论拥塞窗口大小

慢启动工作示例

如下图

  • 在一开始发送方先设置 cwnd = 1,发送第一个报文段M1,接收方收到后确认M1.
  • 发送方收到对M1的确认后,把cwnd从1增大到2,于是接着发送M2和M3两个报文段。接收方收到后发回对M2和M3的确认。
  • 发送方在收到这两个确认后,cwnd就从2增大到4,并可发送M4~M7共4个报文段。

  • 传输轮次(transmission round)

    • 使用慢启动算法时,每经过一个传输轮次,拥塞窗口 cwnd 就加倍
    • 一个传输轮次所经历的时间其实就是往返时间RTT
    • 例如,拥塞窗口 cwnd = 4,这时的往返时间RTT就是发送方连续发送 4 个报文段,并收到这 4 个报文段的确认,总共经历的时间。
    • 传输轮次更加强调:
      • 把拥塞窗口cwnd所允许发送的报文段都连续发送出去,并收到了对已发送的最后一个字节的确认
  • 为防止拥塞窗口cwnd增长过大导致拥塞,设置一个慢启动门限ssthresh

    • cwnd < ssthresh时,使用慢启动算法
    • cwnd > ssthresh时,停止使用慢启动算法而改用拥塞避免算法
    • cwnd = ssthresh时,可使用慢启动算法或拥塞避免算法
拥塞避免
  • 拥塞避免算法的思路
    • 让拥塞窗口cwnd缓慢地增大,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加 1,而不是加倍,使拥塞窗口cwnd按线性规律缓慢增长
  • 拥塞发生时的处理
    • 无论在慢启动阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(没有按时收到确认),就要把慢启动门限ssthresh改为出现拥塞时的发送方窗口值的一半(但不能小于2)
    • 然后把拥塞窗口cwnd重新设置为 1,执行慢启动算法
    • 这样做的目的:迅速减少注入到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕

慢启动和拥塞避免过程示例

  • TCP 连接初始化时,拥塞窗口cwnd=1,慢启动门限ssthresh=16,设发送窗口宽度=拥塞窗口宽度
  • 在慢开始算法阶段,发送端每收到一个确认,就把cwnd加倍,即每经过1个往返时间RTT,拥塞窗口cwnd加倍
  • 当拥塞窗口cwnd≥慢启动门限ssthresh时,进入拥塞避免阶段,每经过1个往返时间RTT,拥塞窗口cwnd+1
  • 假定当拥塞窗口cwnd=24时发生了拥塞,ssthresh减为12,拥塞窗口cwnd=1,并重新开始慢启动过程
  • 注意:TCP中窗口宽度和门限值均以字节为单位,本例中为MSS倍数

  • 上图可以看出

    • 在拥塞避免阶段,拥塞窗口是按照线性规律增大的,这常称为加法增大AI((additive increase))。
    • 而一旦出现超时或3个重复的确认(快重传),就要把门限值设置为当前拥塞窗口值的一半,并大大减小拥塞窗口的数值,这场称为乘法减小MD(multiplicative decrease)。
    • 二者合在一起就是所谓的 AIMD 算法。
  • 加法增大

    • 执行拥塞避免算法后,每经过一个往返时间RTT,把拥塞窗口cwnd增加一个MSS大小,使拥塞窗口缓慢增大,以防止网络过早出现拥塞
  • 乘法减小

    • 不论在慢启动阶段还是拥塞避免阶段,只要出现一次超时(即网络拥塞),就把慢启动门限ssthresh减小到拥塞窗口的一半
    • 当网络频繁出现拥塞时,ssthresh值下降得很快,以大大减少注入到网络中的分组数

考研例题

答:

超时后ssthresh=8,因此第三个RTT时间,cwnd = $2^3$ = 8 = sstresh,因此改用拥塞避免算法,第四个RTT时间后,cwnd增加1,变为9。

答:

显然。

2. 快重传和快恢复

快重传算法

快重传算法可以让发送方尽早知道发生了个别报文段的丢失

  • 快重传(fast retransmit)算法思路
    • 快重传算法首先要求接收方不要等待自己发送数据时才进行捎带确认,而是要立即发送确认
    • 即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认
    • 发送方只要接连收到三个重复确认就应当立即重传对方尚未收到的报文段

快重传示例

  • 如下图,接收方收到了M1和M2后都及时发出了确认。
  • 现在接收方没有收到M3但却收到了M4,按照快重传算法,接收方必须立即发送对M2的重复确认
  • 发送方接着发送M5和M6,接收方收到后再次发送对M2的重复确认。
  • 最终,发送方共收到了4个对M2的确认,其中后3个都是重复确认,因此应立即进行重传

快恢复算法
  • 快恢复(fast recovery)算法思路
    • 当发送端收到连续三个重复的确认时,就进行“乘法减小”,把慢启动门限ssthresh减为当前拥塞窗口宽度的一半
    • 接下来不执行慢启动算法,而是开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大
      • 发送方认为现在网络很可能没有发生拥塞(仅有拥塞征兆),因为拥塞时不会有连续多个报文段到达接收方

三、本节小结

TCP 的拥塞控制可以归纳为下图的流程图

  • 发送窗口的上限值
    • 从流量控制角度考虑,发送窗口不能超过对方给出的接收窗口值
    • 综合考虑流量控制和拥塞控制,发送方的发送窗口的上限值应当在接收方窗口rwnd和拥塞窗口cwnd两个者中取较小的一个
      • 发送窗口的上限值 = Min[rwnd, cwnd]
      • 当 rwnd < cwnd 时,是接收方的接收能力限制发送窗口的最大值
      • 当 rwnd > cwnd 时,则是网络的拥塞限制发送窗口的最大值

5.8 TCP的连接管理

  • TCP 运输连接有三个阶段

    1. 连接建立
    2. 数据传送
    3. 连接释放
  • 在 TCP 连接建立过程中要解决三个问题

    1. 要使每一方能够确认对方的存在
    2. 要允许双方协商一些参数(如最大窗口值,是否使用窗口扩大选项和时间戳选项以及服务质量等)
    3. 能够对传输实体资源进行分配(如缓存大小、连接表中的的项目等)
  • TCP连接的建立采用客户/服务方式

    • 客户(client):主动发起连接建立的应用进程
    • 服务器(server):被动等待连接建立的应用进程

一、TCP 的连接建立

  • TCP 建立连接的过程叫做握手,握手需要在client和server之间交换三个TCP报文段,也称为三次握手。
    1. A向B发出连接请求报文段,其首部中的SYN=1,并选择序号seq=x, 表明传送数据时的第一个数据字节的序号是x
      • 需要消耗一个序列号
    2. B收到连接请求后,如同意,则发回确认,其中SYN=1,ACK=1,确认号ack=x+1,自己选择的序号seq=y。
      • 需要消耗一个序列号
    3. A收到后向B给出确认,其ACK=1,确认号ack=y+1
      • 如果不携带数据则不消耗序列号

  • 为什么采用3次握手而不是2次

    • 防止“失效的连接请求”在服务器端占用资源。
      • 客户端发出了连接请求,该数据报并没有丢失,而是在某些网络节点中长时间滞留了,以致延误到连接释放以后的某个时间才到达B
      • B收到此失效的连接请求报文段后,误认为是A又发出一次新的连接请求,于是向A发出确认报文段。
      • 由于现在A并没有发出建立连接的请求,因此不会理睬B的确认,也不会向B发送数据
      • 而B却以为新的运输连接已经建立了(若采用2次握手,那么只要B发出确认,新的连接就已经建立了),并一直等待A发来数据。因此B的许多资源就白白浪费了
  • 3次握手带来的安全问题:TCP SYN Flooding 攻击

    • 攻击者连续发送大量SYN报文,但却不对SYN ACK报文做出响应。结果:服务器内部数据结构满,无法响应正常用户的TCP连接请求
    • 此类攻击大多使用IP地址伪装,使得对攻击源的定位比较困难
    • Linux内核采用了SYN_Cookies机制应对这种攻击
      • 基本思路:服务器返回SYN+ACK时,根据自身特有信息(时间戳、IP地址、端口号等)计算Cookies,作为seq返回给客户端,并在收到对方应答前,不为该连接分配数据结构

二、TCP 的连接释放

  • 连接的释放可由任一方发起
  • 假定A主动关闭连接
    1. A发送报文段,其首部的 FIN=1,序号seq=u
    2. B发出确认,ACK=1,确认号ack=u+1,序号seq = v
    3. A→B方向的连接被释放,此时连接处于半关闭状态,B若发送数据,A仍要接收
    4. 若B已经没有要向A发送的数据,就向A发送连接释放报文(FIN=1, ACK=1)
    5. A收到后,发出确认,其中ACK=1,确认号ack=w+1,序号seq=u+1
    6. TCP连接必须经过时间2MSL后才真正释放掉

  • 关于MSL
    • Maximum Segment Lifetime,报文段最大存活时间
    • RFC793中建议MSL=2分钟,一般使用更小的值
  • 关闭连接前等待2MSL的原因
    • 为了保证A发送的最后一个ACK报文段能够到达B
    • 防止“已失效的连接请求报文段”出现在本连接中
      • A在发送完最后一个ACK报文段后,再经过时间2MSL,就可以使本连接持续的时间内所产生的所有报文段,都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段

三、TCP 的有限状态机