计算机网络基础:运输层

运输层

概述

  • 面向通信部分的最高层、用户功能的最底层
  • 只有位于网络边缘部分的主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组时都只用到下三层的功能。
  • 提供的是进程之间的通信,即“端到端的逻辑通信”(网络层提供的是主机之间的通信)

UDP 与 TCP

UDP TCP
无连接 面向连接
TPDU:UDP报文/用户数据包 TPDU:TCP报文段
支持单播、多播、广播 支持单播
不提供可靠交付 提供可靠交付
简单 复杂
直播、视频流推送 电子邮件、文件传输
DNS DHCP RIP HTTP SMTP FTP

端口

SAP 即服务访问点,IP 地址是网络层的 SAP,MAC 地址是数据链路层的 SAP,端口是运输层服务访问点(TSAP)

  • 使用协议端口号(端口)来识别进程
  • 16位,允许有 65536 个不同的端口号
  • 端口号只具有本地意义,不同计算机的相同端口号没有联系
  • 端口号分类:
    • 服务端端口号:

      • 熟知端口:0 ~ 1023
      • 登记端口号:1024 ~ 49151
    • 客户端端口号(短暂端口号、临时端口号):49152 ~ 65535

套接字(Socket)

Socket = IP 地址 : 端口号,用于标识网络中一台主机及其上的一个应用进程。

常见的基于 TCP 或 UDP 的应用层协议

TCP:文件传输协议(FTP)、超文本传输协议(HTTP)、远程登陆(TELNET)

UDP:小文件传输协议(TFTP)、DNS、SNMP、实时传输协议(RTP)

HTTP 3 使用的是 UDP 协议

HTTP 2 协议基于 TCP 有序字节流实现,因此应用层的多路复用并不能做到无序地并发,在丢包场景下会出现队头阻塞问题。如下面的动态图片所示,服务器返回的绿色响应由 5 个 TCP 报文组成,而黄色响应由 4 个 TCP 报文组成,当第 2 个黄色报文丢失后,即使客户端接收到完整的 5 个绿色报文,但 TCP 层不会允许应用进程的 read 函数读取到最后 5 个报文,并发成了一纸空谈:

动图

分别使用 Packet Header 和 QUIC Frame Header 实现可靠连接(重传)和有序字节流。

用户数据报协议 UDP

在 IP 的数据报服务上提供功能

  1. 运输层协议复用和分用功能

    运输层的复用:不同的应用进程可以使用相同的运输层协议

    运输层的分用:接收方的运输层在收到报文后,剥去报文的首部能够把这些数据正确交付目的应用进程

  2. 差错检测功能

image-20211221144430485

特点

  1. 无连接的,故没有建立连接的时延,速度更快
  2. 无需维护连接的状态,故能支持更多的客户机
  3. 面向报文。对应用层的报文不合并不拆分,保留边界,因此应用层使用 UDP 协议的时候应该选择合适的报文大小,避免数据部分太小或在网络层进行分片后影响 IP 层的效率
  4. 无拥塞控制,故不会被拥塞影响发送速率
  5. 支持一对一、一对多、多对一、多对多的交互通讯
  6. 首部开销小,8 字节,TCP 有 20 字节
image-20211221144654170

首部格式

  1. 源端口:2 字节(运输层的复用和分用)
  2. 目的端口:2 字节
  3. 长度:2 字节
  4. 检验和:2 字节(可选,如果不想使用全 0 即可)

传输流程

当传输层从 IP 层收到 UDP 数据报时,就根据首部中的目的端口,将数据报交给上层应用进程,若发现端口号不正确,则丢弃并由 ICMP 发送“端口不可达”差错报文

UDP 校验和

  1. 添加伪首部(12 B,包含源 IP 地址、目的 IP 地址、0、17、UDP 长度)。

  2. 计算校验和:和 IP 数据报的计算方法相似,但是 IP 数据报的校验和只校验首部,UDP 的校验和校验的是首部和数据。

    先把全 0 放入校验和字段并添加伪首部,然后以 2 字节(16 位)为单位划分 UDP 数据报,若数据报长度为奇数个字节则加一个全 0 字节,将划分的所有数以反码的形式相加,再对和取二进制反码,此即为校验和。

    伪首部和添加的全 0 字节均不发送

  3. 发送方加入伪首部(若数据报长度为奇数个,则加入一个全 0 字节),以同样的方式求和,无差错时结果应该是全 1 。

TCP

TCP 特点

  • 面向连接
  • 可靠交付(无差错、不丢失、不重复、有序)
  • 端到端的(进程到进程的)
  • 全双工(要求发送方和接收方都设置缓存)
  • 面向字节流
    • 不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系。
    • 保证发出和接收的字节流一致
    • 如:发送了10个数据块, 1000个字节;接收到5个数据块,1000个字节

TCP 连接

  • 基本抽象:连接

  • 两个端点,端点成为套接字:socket

  • 套接字 = IP:端口

  • 连接唯一地被通信两端的两个端点所确定

    TCPConnection::={socket1,socket2}=(IP1:port1)(IP2:port2)\begin{aligned} TCP Connection &::=\{socket1, socket2\} \\ &= {(IP1: port1),(IP2: port2)} \end{aligned}

TCP 报文段首部格式

20 B固定 + 4n 扩展(总长度小于 60 B)

  • 序号是指字节流中位于本报文段的第一个字节的序号
image-20211221153138926
  • 最大报文长度(MSS):接收方所能接受的报文段的数据字段的最大长度。

TCP 可靠传输的实现

通过校验(与 UDP 的校验和一致)、序号、确认、重传实现

序号:TCP 将数据视为无结构但有序的字节流,对每个字节进行编号,报文段首部的序号字段即为该报文段第一个字节的序号。

确认:

  • 报文段首部的确认号是期望收到的下一个字节的序号,若 1 ~ 7 字节中 3~5 字节丢失,则即便 6~7 字节已经收到,确认号仍为 3
  • 已发送未确认的报文段将在缓冲区保存,以便重传

重传:

  • 超时:通过自适应算法(根据报文段的 RTT 计算加权平均时间 RTTs)来设置计时器的超时时间(略大于 RTTs),超时后则重传
  • 冗余 ACK:当收到大于期望序号的报文段时,就发送一个冗余 ACK,指明期望收到的字节序号。当收到 3 个冗余 ACK 时即刻对该 ACK 指明的序号进行重传,称为“快速重传”
  • TCP 并非使用 GBN(回退 N) ,若 1 ~ 5 报文段中 2 丢失,则只需要重传 2,TCP 缓冲会保留 3~5,随后会进行累积确认

TCP 流量控制

利用滑动窗口实现,窗口大小有两种方法确定:

  • 接收方动态地调整 TCP 报文段中的“窗口”字段值,称为接收窗口 rwnd

    例:首部 ack = 201,rwnd = 300,则允许发送的为 201 ~ 500 序号的字节

  • 发送方根据当前网络状态自主决定,称为拥塞窗口 cwnd

死锁问题:在连接建立的时候,接收端告知发送端自己的接收窗口是多少,在接收方窗口满后,发送方停止发送,而窗口内的数据处理完后,接收方发送的新的窗口大小的报文段丢失,则发送方一直等待、接收方也等待,发生死锁。

解决死锁

  • TCP 为每一个连接设有一个持续计时器,TCP 连接的一方收到对方的零窗口通知后就启动计时器
  • 计时器到期就发送零窗口探测报文段,而对方就在确认这个探测报文段时给出了现在的窗口值
  • 若窗口仍然是 0 ,则重新设置计时器。

糊涂窗口综合症:接收方窗口中处理完成一字节后立马告诉了发送端,导致发送端一直发送很少的数据,数据传输效率很低。

解决糊涂窗口综合症

  • 接收方主动要求发送数据,则将缓存中的数据全部发送(PUSH)
  • 已有足够空间容纳一个最长的报文段或接收缓存有一半的空闲空间,再发出确认报文

image-20211221192527925

TCP 拥塞控制

  • TCP 采用基于窗口的方法进行拥塞控制,该方法属于闭环控制方法
  • TCP发送方维持一个拥塞窗口 cwnd (Congestion Window),根据网络的拥塞情况调整 cwnd
  • 发送窗口值为 min(rwnd,cwnd)
  • 总结一下就是在开始和超时时执行慢开始和拥塞避免,在收到重复 ACK 时执行快重传和快恢复

拥塞

  • 对网络中某资源的需求超过了该资源的可用部分
  • 最坏结果:系统崩溃

原因:

  1. 点缓存的容量太小;
  2. 链路的容量不足;
  3. 处理机处理的速率太慢;
  4. 拥塞本身会进一步加剧拥塞;

拥塞判断

  1. 重传定时器超时
  2. 收到三个重复的 ACK

闭环控制

(1) 监测网络系统,以便检测到拥塞在何时、何处发生。
(2) 将拥塞发生的信息传送到可采取行动的地方。
(3) 调整网络系统的运行以解决出现的问题。

四种拥塞控制算法

慢开始

拥塞窗口随着不超时的确认报文段数量的增加而加倍不超过慢开始的门限值(ssthresh 阈值),慢开始后改用拥塞避免算法

增加的顺序:

cwnd = 1 -> 收到确认 -> cwnd = 2 -> 收到两个 ACK(连续 ARQ 中为对前两个报文段的累积确认) -> cwnd = 4 …

也就是每经过一个传输轮次后拥塞窗口就增加,时间为 RTT (连续发出 cwnd 个报文,收到 cwnd 个确认所需的时间)

image-20211223152150387

拥塞避免

在执行慢开始达到慢开始门限后,在出现超时之前,每经过一个传输轮次就使 cwnd + 1;

无论是在慢开始阶段还是拥塞避免阶段,只要发送方判断网络出现拥塞,则迅速减少主机发送到网络中的分组数:

  1. 慢开始门限( ssthresh )值设置为当前窗口值的一半,但不小于 2
  2. cwnd = 1
  3. 执行慢开始算法

目的:使得路由器有足够的时间把积压的分组处理完

cwnd < ssthresh 时,使用慢开始算法

cwnd > ssthresh 时,使用拥塞避免

cwnd = ssthresh 时两者均可,常用后者

快重传

发送方只要一连收到 3 个重复确认,就立即重传(即重传机制中的冗余 ACK 机制对拥塞控制有好处)

使网络吞吐量提高约 20%

没有取消重传计时器

快恢复

收到 3 个重复确认后,执行快恢复算法:

  1. ssthresh = cwnd / 2
  2. cwnd = ssthresh(区别于超时时直接设置为 1)
  3. 执行拥塞避免

ARQ 协议

自动重传请求(Automatic Repeat-reQuest),是 OSI 模型中数据链路层和传输层的纠错协议,分为:

  • 停止等待 ARQ 协议
  • 连续 ARQ 协议

现在广泛使用的协议在运输层实现的 ARQ

停止等待 ARQ 协议

每发完一个分组就停止发送,等待确认

接收方检测出了差错或分组未送达接收方,则不会发送确认分组,此时发送方必须重发分组

重传:设置缓冲区便于重传,在收到确认时删除

  • 超时重传

  • 确认丢失:ACK 信息丢失,导致发送方重传,此时接收方丢弃分组且发送确认

  • 确认迟到:ACK 信息迟到:发送方丢弃重复确认,接收方丢弃重复分组且再次确认

检测重复分组

编号:

  1. 为每一个发送的分组进行编号,若收到了编号相同的分组,则认为收到了重复分组。
  2. 发送的确认信号也进行编号,确定确认对象

优点:简单 缺点:信道利用率低

连续 ARQ 协议

连续地发送一组数据,不必每发送一个就等待一次,常用滑动窗口实现

  1. 每收到一个确认,发送方就把发送窗口向前滑动。
  2. 接收方一般采用累积确认的方式。
  3. 采用回退N(Go-Back-N)方法进行重传。

滑动窗口协议

发送方

  1. 发送方维持的发送窗口,位于发送窗口内的分组都可连续发送出去,而不需要等待对方的确认。
  2. 收到确认:窗口向前移动

接收方

  1. 收到的分组正确,向前滑动接收窗口
  2. 接受窗口代表允许接收的分组
  3. 对按序到达的最后一个分组发送确认,若丢失了分组,则以上一次累积确认为起点,其后的分组全部重发(回退 N Go-back-N)

冗余 ACK

参见 TCP 可靠传输实现部分

TCP 连接管理

连接端点

TCP 的连接端点是套接字

三个阶段

  1. 连接建立
  2. 数据传送
  3. 连接释放

客户/服务器

  • TCP 连接的建立采用客户服务器方式
  • 主动发起连接建立的应用进程叫做客户
  • 被动等待连接建立的应用进程叫做服务器

TCP 连接的建立

三次握手

  1. 服务器进程创建 TCB (传输控制块),准备接受客户进程的连接请求。建立连接前,服务器处于 LISTEN 状态

  2. 客户端向服务器发送连接请求报文段,首部中的同步位 SYN = 1,并选择初始序号 seq= x(传送的第一个数据字节的序号) 。

    SYN 报文段不能携带数据,且消耗一个序号

    第一次握手,客户进程处于 SYN-SENT 状态

  3. 服务器收到报文后,如同意:发回确认(SYN = 1 ACK=1 确认号ack= x+1 seq = y)。

    确认报文段不能携带数据,且消耗一个序号

    第二次握手,服务器处于 SYN-RCVD 状态

  4. 客户端收到确认报文后向服务器给出确认,并分配缓存和变量,ACK = 1,ack = y + 1,seq = x + 1,通知上层应用连接已经建立。

    可携带数据,若不携带则不消耗序号

    第三次握手,客户处于 ESTABLISTENED 状态

  5. 服务器收到确认后,也通知其上层应用进程:TCP连接已经建立。

    服务器处于 ESTABLISTENED 状态

洪泛攻击

攻击者发送 TCP 的 SYN,服务器返回 ACK 后,该攻击者就不对其进行确认,那么这个 TCP 连接处于挂起状态,所谓的半连接状态。
服务器收不到再确认的话,还会重复发送 ACK 给攻击者,这样就更加浪费服务器资源。
攻击者如果发送非常大量的这种TCP连接,由于每一个都无法完成三次握手,所以服务器上这些 TCP 连接会因为挂起状态而消耗 CPU 和内存,最后服务器可能死机,就无法为正常用户提供服务

TCP 连接的释放

四次握手

  1. 客户端发送连接释放报文段,停止发送数据,关闭 TCP 连接

    FIN = 1,seq = u,其中 u 是前面传送过的数据的最后一个字节序号 + 1

    此时服务器仍能继续发送数据,客户进入 FIN-WAIT-1 状态

  2. 服务器发出确认,通知高层应用连接已经释放,此时客户端向服务器方向的连接已经释放,而服务器还可以向客户端发送数据,需要等待高层应用通知是否还有数据要发送;

    ACK = 1,确认号为ack = u + 1,seq = v,其中 v 是前面传送过的数据的最后一个字节序号 + 1

    服务器进入 CLOSE-WAIT 状态,此时客户到服务器方向的连接已经释放,TCP 连接处于半关闭状态,此时若服务器发送数据,客户仍需接收

  3. 若服务器已经没有数据需要发送给客户端,则通知 TCP 释放连接,发出报文段

    FIN = 1 ACK = 1 seq = w ack = u + 1,其中 seq 修改为 w 是因为在半关闭的情况下,服务器可能仍发送了一些数据

    服务器进入 LAST-ACK 状态

  4. 客户端收到报文后发出确认

    ACK = 1 ack = w + 1,seq = u + 1

    在等待 2MSL(最长报文段寿命)后,客户机才进入 CLOSED 状态

保活计时器

  • 用来防止在TCP连接出现长时期的空闲。
  • 通常设置为2小时 。
  • 过了2小时还没有收到客户的信息,它就发送探测报文段(心跳)。若发送了10个探测报文段(每一个相隔75秒)还没有响应,就假定客户出了故障,因而就终止该连接。