文章目录
-
- 一、概述和传输层服务
-
- [1.1 传输服务和协议](#1.1 传输服务和协议)
- [1.2 传输层 vs 网络层](#1.2 传输层 vs 网络层)
- [1.3 Internet 传输层协议](#1.3 Internet 传输层协议)
- 二、多路复用与解复用
-
- [2.1 多路复用](#2.1 多路复用)
- [2.2 多路复用解复用工作原理](#2.2 多路复用解复用工作原理)
- [2.3 无连接(UDP)多路解复用](#2.3 无连接(UDP)多路解复用)
-
- [2.3.1 无连接多路解复用例子](#2.3.1 无连接多路解复用例子)
- [2.4 面向连接(TCP)的多路复用](#2.4 面向连接(TCP)的多路复用)
-
- [2.4.1 面向连接的解复用:例子](#2.4.1 面向连接的解复用:例子)
- [2.4.2 面向连接的多路复用:多线程Web Server](#2.4.2 面向连接的多路复用:多线程Web Server)
- 三、无连接传输:UDP
-
- [3.1 UDP:用户数据报协议](#3.1 UDP:用户数据报协议)
- [3.2 UDP校验和](#3.2 UDP校验和)
- 四、可靠数据传输(rdt)的原理
-
- [4.1 可靠数据传输:问题描述](#4.1 可靠数据传输:问题描述)
-
- [4.1.1 Rdt1.0:在可靠信道上的可靠数据传输](#4.1.1 Rdt1.0:在可靠信道上的可靠数据传输)
- [4.1.2 Rdt2.0:具有比特差错的信道](#4.1.2 Rdt2.0:具有比特差错的信道)
- [4.1.3 Rdt2.1](#4.1.3 Rdt2.1)
- [4.1.4 Rdt2.2:无NAK的协议](#4.1.4 Rdt2.2:无NAK的协议)
- [4.1.5 Rdt3.0:具有比特差错和分组丢失的信道](#4.1.5 Rdt3.0:具有比特差错和分组丢失的信道)
- [4.1.6 流水线:提高链路利用率](#4.1.6 流水线:提高链路利用率)
- [4.2 通用:滑动窗口(slide window)协议](#4.2 通用:滑动窗口(slide window)协议)
-
- [4.2.1 发送窗口滑动过程------相对表示法](#4.2.1 发送窗口滑动过程——相对表示法)
- [4.2.2 滑动窗口(slide window)协议](#4.2.2 滑动窗口(slide window)协议)
-
- [4.2.2.1 发送窗口(sending window)](#4.2.2.1 发送窗口(sending window))
- [4.2.2.2 接收窗口(receving window)](#4.2.2.2 接收窗口(receving window))
- [4.2.3 正常情况下两个窗口间的互动](#4.2.3 正常情况下两个窗口间的互动)
- [4.2.4 异常情况下GBN的2窗口互动](#4.2.4 异常情况下GBN的2窗口互动)
- [4.2.5 异常情况下SR的2窗口互动](#4.2.5 异常情况下SR的2窗口互动)
- [4.2.6 GBN协议和SR协议的异同](#4.2.6 GBN协议和SR协议的异同)
- [4.2.7 流水线协议:总结](#4.2.7 流水线协议:总结)
- [4.2.8 思考题:窗口的最大尺寸](#4.2.8 思考题:窗口的最大尺寸)
- 五、面向连接的传输:TCP
-
- [5.1 概述](#5.1 概述)
- [5.2 TCP 报文段结构](#5.2 TCP 报文段结构)
- [5.3 可靠数据传输](#5.3 可靠数据传输)
-
- [5.3.1 TCP发送方(简化版)](#5.3.1 TCP发送方(简化版))
- [5.3.2 TCP 发送方事件:](#5.3.2 TCP 发送方事件:)
- [5.3.3 TCP:重传](#5.3.3 TCP:重传)
- [5.3.4 产生TCP-ACK的建议](#5.3.4 产生TCP-ACK的建议)
- [5.3.5 快速重传](#5.3.5 快速重传)
- [5.4 流量控制](#5.4 流量控制)
- [5.5 连接管理](#5.5 连接管理)
-
- [5.5.1 同意建立连接](#5.5.1 同意建立连接)
- [5.5.2 TCP 3次握手](#5.5.2 TCP 3次握手)
- [5.5.3 关闭连接](#5.5.3 关闭连接)
- 六、拥塞控制原理
-
- [6.1 拥塞的原因/代价:场景1](#6.1 拥塞的原因/代价:场景1)
- [6.2 拥塞的原因/代价:场景2](#6.2 拥塞的原因/代价:场景2)
- [6.3 拥塞的原因/代价:场景3](#6.3 拥塞的原因/代价:场景3)
- [6.4 拥塞控制方法](#6.4 拥塞控制方法)
-
- [6.4.1 案例学习: ATM ABR 拥塞控制](#6.4.1 案例学习: ATM ABR 拥塞控制)
- [七、TCP 拥塞控制](#七、TCP 拥塞控制)
-
- [7.1 机制](#7.1 机制)
- [7.2 拥塞感知](#7.2 拥塞感知)
- [7.3 速率控制方法](#7.3 速率控制方法)
- [7.4 TCP拥塞控制和流量控制的联合动作](#7.4 TCP拥塞控制和流量控制的联合动作)
-
- [7.4.1 策略概述](#7.4.1 策略概述)
- [7.4.2 TCP慢启动](#7.4.2 TCP慢启动)
- [7.4.3 AIMD(Additive- Increase, Multiplicative- Decrease)](#7.4.3 AIMD(Additive- Increase, Multiplicative- Decrease))
- [7.4.4 改进](#7.4.4 改进)
- [7.5 总结](#7.5 总结)
- [7.6 TCP吞吐量](#7.6 TCP吞吐量)
- [7.7 TCP公平性](#7.7 TCP公平性)
- 八、总结
一、概述和传输层服务
1.1 传输服务和协议
- 为运行在不同主机上的应 用进程提供逻辑通信
- 传输协议运行在端系统
- 发送方:将应用层的报文分成报文段,然后传输给网络层
- 接收方: 将报文段重组成报文,然后传递给应用层
- 有多个传输层协议可供应选择
- Internet:TCP 和 UDP
1.2 传输层 vs 网络层
- 网络层服务:主机之间的逻辑通信
- 传输层服务 :进程间的逻辑通信
- 依赖于网络层的服务
- 延时、阻塞
- 并对网络层的服务进行加强
- 数据丢失、顺序混乱、加密
- 依赖于网络层的服务
有些服务是可以加强的:不可靠 -> 可靠;安全 但有些服务是不可以被加强的:带宽,延迟
类比:东西2个家庭的通信
Ann家的12个小孩给另Bi家的12个小孩发信
- 主机 = 家庭
- 进程 = 小孩
- 应用层报文 = 信封中的信件
- 传输协议 = Ann 和 Bill
- 为家庭小孩提供复用解复用服务
- 网络层协议 = 邮政服务
- 家庭-家庭的邮包传输服务
1.3 Internet 传输层协议
- 可靠的、保序的传输:TCP
- 多路复用、解复用
- 拥塞控制
- 流量控制
- 建立连接
- 不可靠、不保序的传输:UDP
- 多路复用、解复用
- 没有为尽力而为的IP服务添加更多的额外服务
- 都不提供的服务:
- 延时保证
- 带宽保证
二、多路复用与解复用
2.1 多路复用
2.2 多路复用解复用工作原理
- 解复用原理:TCP或者UDP实体采用哪些信息,将报文段的数据部分交给正确的socket,从而交给正确的进程
- 主机收到IP数据报
- 每个数据包有源IP地址和目标IP地址
- 每个数据报承载一个传输层报文段
- 每个报文段有一个源端口号和目标端口号(特定应用有著名的端口号)
- 主机联合使用IP地址 和端口号将报文段发送给合适的套接字
2.3 无连接(UDP)多路解复用
- 创建套接字:
- 服务器端:
- serverSocket = socket(PF_INET, SOCK_DREAM, 0);
- bind(serverSocket, &sad, sizeof sad); // server和sad指定的端口号绑定
- 客户端:
- ClientSocket = socket(PF_INET, SOCK_DREAM, 0);
- 没有Bind,ClientSocket和os为之分配的某个端口号捆绑(客户端使用什么端口号无所谓,客户端主动找服务器)
- 接收端:
- 在接收端,UDP套接字用二元组标识(目标IP地址、目标端口号)
- 当主机收到UDP报文段:
- 检查报文段的目标端口号
- 用该端口号将报文段定位给套接字
- 如果两个不同源IP地址/源端口号的数据报,但是有相同的目标IP地址和端口号,则被定位到相同的套接字
- 服务器端:
2.3.1 无连接多路解复用例子
- 当主机接收到UDP段时:
- 检查UDP段中的目标端口号
- 将UDP段交给具备那个端口号的套接字
- 具备相同目标IP地址和目标端口号,即使是源IP地址 或/且 源端口号不同的IP数据报,将会被传到相同的目标UDP套接字上
2.4 面向连接(TCP)的多路复用
-
TCP套接字:四元组本地标识:
- 源IP地址
- 源端口号
- 目的IP地址
- 目的端口号
-
解复用:接收主机用这四个值来将数据报定位到合适的套接字
-
服务器能够在一个TCP端口上同时支持多个TCP套接字:
- 每个套接字由其四元组标识(有不同的源IP和源PORT)
-
Web服务器对每个连接客户端有不同的套接字
- 非持久对每个请求有不同的套接字
2.4.1 面向连接的解复用:例子
- p4, p5, p6 都运行在目标主机的80号端口
- 主机A和C 共三个报文段全部指向相同的目标IP和目标端口80,A和C之间IP不同而加以区分,B的P2和P3因为源端口号不同加以区分
- 在目标主机解复用传递给三个不同的应用进程
2.4.2 面向连接的多路复用:多线程Web Server
三、无连接传输:UDP
- ""no frills" "bare bones" Internet 协议
- "尽力而为"的服务,报文段可能丢失
- 丢失
- 送到应用程序的报文段乱序
- 无连接:
- UDP 发送端和接收端之间没有握手
- 每个UDP报文段都被独立地处理
- UDP 被用于:
- 流媒体(丢失不敏感,速率敏感,应用可控制传输速率 )
- DNS
- SNMP
- 在UDP上可行可靠传输
- 在应用层增加可靠性
- 应用特定地差错恢复
3.1 UDP:用户数据报协议
为什么要有UDP?
- 不建立连接(会增加延时)
- 简单:在发送端和接收端没有连接状态
- 报文段的头部很小(开销小)
- 无拥塞控制和流量控制:UDP可以尽可能快的发送报文段
- 应用->传输的速率 = 主机->网络的速率
3.2 UDP校验和
**目标:**检测在被传输报文段中的差错(如比特反转)
发送方:
- 将报文段的内容视为16比特的整数
- 校验和:报文段的加法和(1的补运算)
- 发送方将校验和放在UDP的校验和字段
接收方:
- 计算接收到的报文段的校验和
- 检查计算出的校验和与校验和字段的内容是否相等:
- 不相等------检测到差错
- 相等------没有检测到差错,但也许还是有差错
- 残存错误
例子:
注意:当数字相加时,在最高位的进位要回卷,再加到结果上
例子:两个16比特的整数相加
1 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0
1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
-------------------------------
回卷 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1
-------------------------------
和 1 0 1 1 1 0 1 1 1 0 1 1 1 1 0 0
校验和 0 1 0 0 0 1 0 0 0 1 0 0 0 0 1 1
- 目标端:校验范围 + 校验和 = 1111111111111111 通过校验
- 否则没有通过校验和
- 注:求和时,必须将进位回卷到结果上
四、可靠数据传输(rdt)的原理
- rdt在应用层、传输层和数据链路层都很重要
- 是网络 Top 10 问题之一
**传输层 **为上层提供的服务抽象是:数据可以通过一条可靠的信道进行传输。
- 信道的不可靠特点决定了可靠数据传输协议( rdt )的复杂性
实现这种服务抽象是**可靠数据传输协议(reliable data transfer protocol)**的责任。然而,可靠数据传输协议的下层协议也许是不可靠的,所以十分困难。
4.1 可靠数据传输:问题描述
我们将:
- 渐增式地开发可靠数据传输协议(rdt)地发送方和接收方
- 只考虑单向数据传输
- 但控制信息是双向流动
- 双向的数据传输问题实际上是2个单向数据传输问题的综合
- 使用有限状态机(FSM)来描述发送方和接收方
**状态:**在该状态下,下一个状态只由下一个事件唯一确定
4.1.1 Rdt1.0:在可靠信道上的可靠数据传输
- 下层的信道完全可靠
- 没有比特出错
- 没有分组丢失
- 发送方和接收方的FSM(finite state machine)
- 发送方将数据发送到下层信道
- 接收方从下层信道接收数据
4.1.2 Rdt2.0:具有比特差错的信道
- 下层信道可能会出错,将分组中的比特翻转
- 用校验和来检验比特差错
- 问题:怎样从差错中恢复
- **确认(ACK):**接收方显式地告诉发送方分组已被正确接收
- **否认确认(NAK):**接收方显式地告诉发送方分组发生了差错
- 发送方收到NAK后,发送方重传分组
- rdt 2.0 中的新机制:采用差错控制编码进行差错检测
- 发送方差错控制编码、缓存
- 接收方使用编码检错
- 接收方的反馈:控制报文(ACK,NAK):接收方 -> 发送方
- 发送方收到反馈相应的动作
FSM描述
4.1.3 Rdt2.1
Rdt2.0 的致命缺陷:
- 如果ACK/NAK出错?
- 发送方不知道接收方发生了什么事情!
- 发送方如何做?
- 重传?可能重复
- 不重传?可能死锁(或出错)
- 需要引入新机制
- 序号
- 处理重复
- 发送方在每个分组中加入序号
- 我们仅需0、1即可进行区分
- 如果ACK/NAK出错,发送方重传当前分组
- 接收方丢弃(不发给上层)重复分组
- 发送方在每个分组中加入序号
停等协议
++发送方发送一个分组,然后等待接收方的应答。++
发送方处理出错的ACK/NAK
接收方处理出错的ACK/NAK
发送方:
- 在分组中加入序列号
- 两个序列号(0,1)就足够了
- 一次只发送一个未经确认的分组
- 必须检测ACK/NAK是否出错(需要EDC)
- 状态数变成了两倍
- 必须记住当前分组的序列号为0还是1
接收方:
- 必须检测接收到的分组是否是重复的
- 状态会指示希望接收到的分组的序号为0还是1
- 注意:接收方并不知道发送方是否正确收到了其ACK/NAK
- 没有安排确认的确认
接收方不知道它最后发送的**ACK **/ NAK是否被正确地收到
- 发送方不对收到的ACK/NAK给确认,没有所谓的确认的确认
- 接收方发送ACK,如果后面接收方收到的是:
- 老分组P0?则ACK错误
- 下一个分组?P1,ACK正确
4.1.4 Rdt2.2:无NAK的协议
- 功能同Rdt2.1,但只使用ACK(ack 需要编号)
- 接收方对最后 正确接收的分组发ACK,以替代NAK
- 接收方必须显式地包含被正确接收的分组的序号
- 当收到重复的ACK(如:再次收到ACK0)时,发送方与收到NAK采取相同的动作:重传当前分组
- 通过发送重复的ACK来替代NAK的发送
- 为后面的一次发送多个数据单位做一个准备
- 一次能够发送多个
- 每一个的应答都有:ACK,NACK:麻烦
- 使用对前一个数据单位的ACK,代替本数据单位的NAK
- 确认信息减少一半,协议处理简单
FSM
逻辑还是很简单的
4.1.5 Rdt3.0:具有比特差错和分组丢失的信道
**新的假设:**下层信道可能会丢失分组(数据或ACK)
- 会死锁
- Rdt2.2的机制还不够处理这种状况:
- 校验和
- 序列号
- ACK
- 重传
方法:发送方等待ACK一段合理的时间
- 发送端超时重传:如果到时没有收到ACK->重传
- 问题:如果分组(或ACK)只是被延迟了
- 重传将会导致数据重复,但利用序列号已经可以处理这个问题
- 接收方必须指明被正确接收的序列号
- 需要一个倒计数定时器
发送方的FSM:
Rdt3.0 运行
- 如果超时定时器设置的不合理,导致过早地超时重传,那么会使得多次重发packet,但是不会出错。但是效率比较低,一半的分组和确认时重复的
- 设置一个合理的超时时间也非常重要
Rdt3.0 的性能
- Rdt3.0 可以工作,但链路容量比较大的情况下,性能很差
- 链路容量很大,一次发一个PDU 的不能够充分利用链路的传输能力
- 例:1 Gbps 的链路,15ms端-端传播延时,分组大小为1KB:
- U s e n d e r = 利用率 − 忙于发送的时间比例 U_{sender} = 利用率 - 忙于发送的时间比例 Usender=利用率−忙于发送的时间比例
- 每30ms发送1KB的分组->270Kbps = 33.75kB/s 的吞吐量(在1Gbps链路上)
- 瓶颈在于: 网络协议限制了物理资源的利用!
- 协议本身只允许一次发一个,导致利用率太低了!
- 如何解决?------流水线协议
4.1.6 流水线:提高链路利用率
增加每次发送分组的数目,极大地提高了链路利用率
随着n的增大,瓶颈将会转移到链路带宽上
流水线:允许发送方在未得到对方确认 的情况下一次发送多个分组
- 必须增加序号的范围:用多个bit表示分组的序号
- 在发送方/接收方要有缓冲区
- 发送方缓冲:未得到确认,可能需要重传
- 接收方缓冲:上层用户取用数据的速率 ≠ 接收到的数据速率;接收到的数据可能乱序,排序交付(可靠)
两种通用的流水线协议:回退N步(GBN) 和 选择重传(SR)
4.2 通用:滑动窗口(slide window)协议
- 发送缓冲区
- 形式:内存中的一个区域,落入缓冲区的分组可以发送
- 功能:用于存放已发送,但是没有得到确认的分组
- 必要性:需要重发时可用
- 发送缓冲区的大小:一次最多可以发送多少个未经确认的分组
- 停止等待协议=1
- 流水线协议>1,合理的值,不能很大,链路利用率不能够超100%
- 发送缓冲区中的分组
- 未发送的:落入发送缓冲区的分组,可以连续发送出去;
- 已经发送出去的、等待对方确认的分组:发送缓冲区的分组只有得到确认才能删除
4.2.1 发送窗口滑动过程------相对表示法
- 采用相对移动方式表示,分组不动
- 可缓冲范围移动,代表一段可以发送的权力
4.2.2 滑动窗口(slide window)协议
- 发送窗口:发送缓冲区内容的一个范围
- 那些已发送 但是未经确认分组的序号构成的空间
- 发送窗口的最大值 <= 发送缓冲区的值
- 一开始:没有发送任何一个分组
- 后沿 = 前沿
- 之间为发送窗口的尺寸=0
- 每发送一个分组,前沿前移一个单位
发送窗口的移动->前沿移动
- 发送窗口前沿移动的极限:不能够超过发送缓冲区
发送窗口的移动->后沿移动
- 条件:收到老分组的确认
- 结果:发送缓冲区罩住新的分组,来了分组可以发送
- 移动的极限:不能够超过前沿
4.2.2.1 发送窗口(sending window)
4.2.2.2 接收窗口(receving window)
接收窗口(receiving window)= 接收缓冲区
-
接收窗口用于控制哪些分组可以接收
- 只有收到分组序号落入接收窗口内才允许接收
- 若序号在接收窗口之外,则丢弃
-
接收窗口尺寸Wr = 1,则只能顺序接收
-
接收窗口尺寸Wr > 1,则可以乱序接收
- 但是提交给上层的分组,要按序
-
例子:Wr = 1,在0的位置:只有0号分组可以接收
向前滑动1个,罩在1的位置,如果来了第2号分组,则丢弃,因为第2号分组不在窗口内
- 接收窗口的滑动和发送确认
- 滑动:
- 低序号的分组到来,接收窗口移动
- 高序号分组乱序到来,缓存但不交付(因为要实现rdt,不允许失序),不滑动
- 发送确认:
- 接收窗口尺寸=1:发送连续收到的最大分组确认(GBN协议,累计确认,即发送一个确认,代表前面的分组都已确认)
- 接收窗口尺寸>1:收到分组,发送那个分组的确认(SR协议,非累计确认)
- 滑动:
4.2.3 正常情况下两个窗口间的互动
- 发送窗口
- 有新的分组落入发送缓冲区范围,发送->前沿滑动
- 来了老的低序号分组的确认->后沿向前滑动->新的分组可以落入发送给缓冲区的范围
- 接收窗口
- 收到分组,落入到接收窗口范围内,接收
- 是低序号,发送确认给对方
- 发送端上面来了分组->发送窗口滑动->接收窗口滑动->发确认
4.2.4 异常情况下GBN的2窗口互动
- 发送窗口
- 新分组落入发送缓冲区范围,发送->前沿滑动
- 超时重发机制让发送端将发送窗口中的所有分组发送出去
- 来了老分组的重复确认->后沿不向前滑动->新的分组无法落入发送缓冲区的范围(此时如果发送缓冲区有新的分组可以发送)
- 接收窗口
- 收到乱序分组,没有落入到接收窗口的范围内,抛弃
- (重复)发送老分组的确认,累计确认
4.2.5 异常情况下SR的2窗口互动
- 发送窗口
- 新分组落入发送缓冲区范围,发送->前沿滑动
- 超时重发机制让发送端将超时的分组重新发送出
- 来了乱序分组的确认->后沿不向前滑动->新的分组无法落入发送缓冲区的范围(此时如果发送缓冲区有新的分组可以发送)
- 接收窗口
- 收到乱序分组,落入到接收窗口的范围内,接收
- 发送该分组的确认,单独确认
4.2.6 GBN协议和SR协议的异同
- 相同之处
- 发送窗口>1
- 一次能够可发送多个未经确认的分组
- 不同之处
- GBN(Go Back N) :接收窗口尺寸=1
- 接收端:只能顺序接收
- 发送端:从表现来看,一旦一个分组没有发成功,如:0,1,2,3,4;假如1未成功,234都发出去了,要返回1再发送:GB1(Go Back to 1)
- SR(Selective repeat) :接收窗口尺寸>1
- 接收端:可以乱序接收
- 发送端:发送0,1,2,3,4,一旦1未成功,2,3,4 已发送,无需重发,选择性发送1(Selective repeat 1)
- GBN(Go Back N) :接收窗口尺寸=1
4.2.7 流水线协议:总结
Go-back-N:
- 发送端最多在流水线中有N个未确认的分组
- 接收端只是发送累计型确认cumulative ack
- 接收端如果发现gap,不确认新到来的分组
- 发送端拥有对最老的未确认分组的定时器
- 只需设置一个定时器
- 当定时器到时时,重传所有未确认分组
Selective Repeat
- 发送端最多在流水线中有N个未确认的分组
- 接收方对每个到来的分组单独确认individual ack(非累计确认)
- 发送方为每个未确认的分组保持一个定时器
- 当超时定时器到时时,只是重发到时的未确认分组
GBN:发送方扩展的FSM
GBN:接收方扩展的FSM
选择重传SR
- 接收方对每个正确接收的分组,分别发送 ACKn (非累计确认)
- 接收窗口 > 1
- 可以缓存乱序的分组
- 最终将分组按顺序交付给上层
- 接收窗口 > 1
- 发送方只对那些没有收到ACK的分组进行重发------选择性重发
- 发送方为每个未确认的分组设定一个定时器
- 发送窗口的最大值(发送缓冲区)限制发送未确认分组的个数
选择重传
选择重传SR的运行
对比GBN和SR
- 适用范围
- 出错率低:比较适合GBN,出错非常罕见,没有必要用复杂的SR,为罕见的事件做日常的准备和复杂处理
- 链路容量大(延迟大、带宽大):比较适合SR而不是GBN,一点出错代价太大
4.2.8 思考题:窗口的最大尺寸
序号大小与窗口大小之间的关系?
假如用 n bit 来代表分组序号,那么 GBN 发送窗口最大尺寸为:2^n - 1 ,SR 发送窗口最大尺寸为:2^(n - 1)
原因:
窗口协议中,序号是循环使用的(序号 mod 2^n 循环使用),当发送窗口过大,会导致序号回绕时,接收方无法确认该分组是旧的分组还是新的分组。
对于GBN:如果我们大于 2^n - 1,比如 2^n,那么我们发送了 2^n 的分组后,发送方会再次从0开始发送,这个时候,接收方就分不清到底是旧分组的重发还是新的分组了。比如 你后沿把0扔出去,前沿 0又进来了,发送0,接收方看来,这可能是旧0的重发,也可能是新0.
对于SR:2^{n - 1} 的大小 保证了 [0, 2^{n - 1} - 1] 和 [2^{n - 1}, 2^n - 1] 在两个窗口内,当序号回绕时,新窗口的分组序号和上一个窗口的分组序号不同,接收方可以判断是新窗口的分组还是旧窗口的分组重传
五、面向连接的传输:TCP
5.1 概述
-
点对点
- TCP连接是点对点的,一个发送方,一个接收方
-
可靠的、按顺序的字节流:
- 没有报文边界
-
管道化(流水线)
- TCP拥塞控制和流量控制设置窗口大小
-
发送和接收缓存
- 发送方发送的数据由TCP引导到发送缓存,适时发送,相对应的,会存在一个接收缓存
-
全双工数据:
- 在同一连接中数据流双向流动
- MSS(max segment size) :报文段里应用层数据的最大长度,而不是指包括首部的TCP报文段的最大长度
- 在同一连接中数据流双向流动
-
面向连接:
- 在数据交换之前,通过握手(交换控制报文)初始化发送方、接收方的状态变量
-
有流量控制:
- 发送方不会淹没接收方
5.2 TCP 报文段结构
字节流会被划分为一个个的MSS,TCP为每块客户数据配上一个TCP首部,从而形成多个TCP报文段(TCP segment)
TCP报文段的结构如下:
- 源端口号、目标端口号
- 序号和确认号用于实现rdt
- 首部长度
- 6个标志字段:
- U:紧急数据
- A:ACK,用于指示字段中的值是有效的
- P:PSH:马上推出数据,即置1时,接收方应立即将数据交给上层
- RST,SYN,FIN 的组合用于连接的建立和拆除
TCP 序号、确认号
序号:
- 报文段首字节在字节流的编号
确认号
- 期望从另一方收到的下一个字节的序号
- 累积确认
- 确认号有没有用:看 ACK标志位
Q:接收方如何处理乱序的报文段?
A:没有规定,取决于实现者自己
- A 发送第42字节,期望B从79开始传
- B 发送第79个字节,期望A从43开始传
- ......
TCP往返延时(RTT)和超时
**Q:**怎样设置TCP超时?
- 比 RTT 要长
- 但 RTT 是变化的
- 太短:太早超时
- 不必要的重传
- 太长:对报文段丢失反应太慢,消极
Q:怎样估计RTT?
- SampleRTT :测量从报文段发出到收到确认的时间
- 如果有重传,忽略此次测量
- SampleRTT 会变化,因此估计的RTT 应该比较平滑
- 对几个最近的测量值求平均 ,而不是仅用当前的SampleRTT
如何求平均?------指数加权
EstimatedRTT = (1 - α) * EstimatedRTT + α * SampleRTT
- 指数加权移动平均
- 过去样本的影响呈指数衰减
- α 推荐值: = 0.125 R
设置超时
-
EstimatedRTT + 安全边界时间
- EstimatedRTT 变化大(方差大)->较大的安全边界时间
-
SampleRTT 会偏离 EstimatedRTT多远(也是用指数加权平均来计算):
**DevRTT = (1 - β) * DevRTT + β * |SampleRTT - EstimatedRTT| **
(推荐值:β = 0.25)
超时时间间隔设置为:
TimeoutInterval = EstimatedRTT + 4 * DevRTT
5.3 可靠数据传输
- TCP 在 IP 不可靠服务的基础上建立了rdt
- 管道化的报文段
- GBN or SR
- 累计确认(像GBN)
- 单个重传定时器(像GBN)
- 是否可以接受乱序的,没有规范
- 管道化的报文段
- 通过以下事件触发重传
- 超时(只重发那个最早的未确认段:SR)
- 重复的确认
- 例子:收到了 ACK50,之后又收到了3个ACK50
- 首先考虑简化的TCP发送方:
- 忽略重复的确认
- 忽略流量
5.3.1 TCP发送方(简化版)
5.3.2 TCP 发送方事件:
从应用层接收数据:
-
从 nextseq 创建报文段
-
序号 nextseq 为报文段首字节的字节流编号
-
如果还没有运行,启动定时器
-
定时器与最早未确认的报文段关联
-
过期间隔
TimeOutInterval
-
超时:
- 重传后沿最老的报文段
- 重新启动定时器
收到确认:
- 如果是对尚未确认的报文段确认
- 更新已被确认的报文序号
- 如果当前还有未被确认的 报文段,重新启动定时器
- 注释:
- SendBase - 1:最后一个累积确认的字节
5.3.3 TCP:重传
5.3.4 产生TCP-ACK的建议
- case1:不立即发ACK,在超时时间内等待别的报文段,如果实在没有的话,则发送一个ACK
- case2:当前已经攒了一个ACK,然后又到了一个按序报文段,赶紧把手里这个发出去
- case3:乱序到达一个报文段,那么就发送重复ACK
- case4:乱序到了一个报文段产生了一个gap:
-
如果来了个完全补齐gap的报文段,那么赶紧发送乱序报文段的期待
-
如果是部分补齐gap,假如填充到y1,那么发送起始字节为y1的期待
-
5.3.5 快速重传
-
超时周期往往太长:
- 在重传丢失报文段之前的延时太长
-
通过重复的ACK来检测报文段丢失
- 发送方通常连续发送大量报文段
- 如果报文段丢失,通常会引起多个ACK重复
-
如果发送方收到同一数据 的3个冗余ACK,重传最小序号的段:
-
快速重传:在定时器过时之前重发报文段
-
它假设跟在被确认的数据后面的数据丢失了
-
第一个ACK是正常的
-
收到第二个该段的ACK,表示接收方收到一个该段后的乱序段
-
收到第3、4个该段的ACK,表示接收方收到该段后的2、3个乱序段
说明:该段很可能丢失了!!!直接在超时之前重发
-
-
下面是 富哥速速v我50的例子(
快速重传算法
else 逻辑隐含的是:y = base,因为base前面的都已经确认所以不可能存在 y < base
5.4 流量控制
流量控制:接收方控制发送方,不让发送方发送的太多、太快以至于让接收方的缓冲区溢出
- 接收方在其向发送方的TCP 段头部的rwnd 字段"通告"其空闲buffer 大小
- RcvBuffer 大小通过 socket 选项设置(典型默认大小为4096字节)
- 很多操作系统自动调整RcvBuffer
- 发送方限制未确认("in-flight")字节的个数 ≤ 接收 方发送过来的 rwnd 值
- 保证接收方不会被淹没(不会缓冲区溢出)
5.5 连接管理
- 在正式交换数据之前,发送方和接收方握手建立通信关系:
- 同意建立连接(每一方都知道对方愿意建立连接)
- 同意连接参数
5.5.1 同意建立连接
在网络中,2次握手建立连接可行吗?
- 变化的延迟(连接请求的段没有丢,但可能超时)
- 由于丢失造成的重传 (e.g. req_conn(x))
- 报文乱序
- 相互看不到对方
2次握手的失败场景:
- 发了两个连接请求
- 建立连接后,发送两次数据
- 结束后,老请求终于到达了服务器,又建立了连接
- 老数据也终于到达了服务器,被接受
- 啊?
5.5.2 TCP 3次握手
解决方案:变化的初始序号+双方确认对方的序号(3次握手)
3次握手解决:半连接和接收老数据问题
对于半连接:老 req 的 acc 会被拒绝掉
对于接收老数据:
- 情况1:由于连接不存在,数据会被扔掉
- 情况2:由于序号不在当前序号范围内,所以被扔掉
- 我们不得不承认,序号回滚回来会有旧数据的序号在当前范围内的可能,但是概率很低。网络无法解决所有问题
3次握手的有限状态机:
5.5.3 关闭连接
- 客户端、服务器分别关闭他自己这一侧的连接
- 发送 FIN bit = 1 的 TCP 段
- 一旦接收到FIN,用ACK回应
- 接到FIN段,ACK可以和它自己发出的FIN段一起发送
- 可以处理同时的FIN交换
- 客户端发送FIN = 1,进入FIN-WAIT1状态
- 接收到 服务器的ACK,进入 FIN-WAIT2状态
- 收到服务器的FIN = 1 或者 超时,关闭连接
前面也说了网络无法解决所有的问题,TCP 的3次握手为 SYN 洪泛攻击提供了环境。
在三次握手下,服务器得到一个 SYN 会建立半连接并分配资源,当超时后才会断开并回收。
攻击者发送大量的TCP SYN 报文段,导致服务器不断建立半连接,使得服务器资源消耗殆尽。
现在大多数主流操作系统都部署了SYN cookie来防御这类攻击。
六、拥塞控制原理
拥塞:
- 非正式的定义:"太多的数据需要网络传输,超过了网络的处理能力"
- 与流量控制不同
- 拥塞的表现:
- 分组丢失(路由器缓冲区溢出)
- 分组经历比较长的延迟(在路由器的队列中排队)
- 网络中前10位的问题
6.1 拥塞的原因/代价:场景1
- 2个发送端,2个接收端
- 一个路由器,具备无限大的缓冲
- 输出链路带宽:R
- 没有重传
缓冲无限大的情况下,分组不会丢,但是会让延迟大的难以接受。
6.2 拥塞的原因/代价:场景2
- 一个路由器,有限的缓冲
- 分组丢失时,发送端重传
- 应用层的输入 = 应用层的输出: λ i n = λ o u t \lambda_{in} = \lambda_{out} λin=λout
- 传输层的输入包括重传: λ i n ′ ≥ λ i n \lambda'{in} \ge \lambda{in} λin′≥λin
理想化:发送端有完美的信息
发送端知道什么时候路由器的缓冲是可用的
- 在缓冲可用时发送
- 不会丢失: λ i n ′ = λ i n \lambda'{in} = \lambda{in} λin′=λin
理想化: 掌握丢失信息
- 分组可以丢失,在路由器由于缓冲器满而被丢弃
- 如果知道分组丢失了,发送方重传分组
现实情况:重复
- 分组可能丢失,由于缓冲器满而被丢弃
- 发送端最终超时,发送第2个拷贝,2个分组都被传出
输出比输入少原因:
- 重传的丢失分组
- 没有必要重传的重复分组
拥塞的"代价":
- 为了达到一个有效输出,网络需要做更多的工作(重传)
- 没有必要的重传,链路中包括了多个分组的拷贝
- 是那些没有丢失,经历的时间比较长(拥塞状态)但是超时的分组
- 降低了的"goodput"
6.3 拥塞的原因/代价:场景3
- 4个发送端
- 多重路径
- 超时 / 重传
**Q:**当 λ i n λ i n ′ 增加时,会发生什么? \lambda_{in} \lambda'_{in} 增加时,会发生什么? λinλin′增加时,会发生什么?
**A:**当红色的 λ i n ′ \lambda'_{in} λin′ 增加时,所有到来的蓝色分组都在最上方的队列中丢弃了,蓝色吞吐->0
又一个拥塞的代价:
- 下游路由器的分组丢失时,相当于上游白传输了,造成了上游传输能力的浪费
6.4 拥塞控制方法
2种常用的拥塞控制方法:
端到端拥塞控制:
- 没有来自网络的显示反馈
- 端系统根据延迟和丢失事件推断是否有拥塞
- TCP采用的方法
网络辅助的拥塞控制:
- 路由器提供给端系统以反馈信息
- 单个 bit 置位,显示有拥塞 (SNA,DECbit,TCP/IP ECN,ATM)
- 显式提供发送端可以 采用的速率
6.4.1 案例学习: ATM ABR 拥塞控制
ABR:available bit rate:
- "弹性服务"
- 如果发送端的路径"轻载"
- 发送方使用可用带宽
- 如果发送方的路径拥塞了
- 发送方限制其发送的 速度到一个最小保障 速率上
RM (资源管理) 信元:
信元可以看作一个分组:53字节,其中5个字节为头部
- 向发送端发送,在数据信元中间隔插入
- RM信元中的比特被交换机设置("网络辅助")
- NI bit:no increase in rate(轻微拥塞)速率不要增加了
- CI bit:congestion indication 拥塞指示
- 发送端发送的RM信元被接收端返回,接收端不做任何改变
- 在RM 信元中的2 个字节 **ER (explicit rate)**字段
- 拥塞的交换机可能会降低信元中ER的值
- 发送端发送速度因此是最低的可支持速率
- 数据信元中的EFCI bit : 被拥塞的交换机设置成1
- 如果在管理信元RM前面的数据信元EFCI被设置成了1, 接收端在 返回的RM信元中设置CI bit
七、TCP 拥塞控制
7.1 机制
- 端到端的拥塞控制机制
- 路由器不向主机有关拥塞的反馈信息
- 路由器的负担较轻
- 符合网络核心简单的 TCP/IP 架构原则
- 端系统根据自身得到的信息,判断是否发生拥塞,从而采取动作
- 路由器不向主机有关拥塞的反馈信息
拥塞控制的几个问题
- 如何检测拥塞
- 轻微拥塞
- 拥塞
- 控制策略
- 在拥塞发送时如何动作,降低速率
- 轻微拥塞,如何降低
- 拥塞时,如何降低
- 在拥塞缓解时如何动作,增加速率
- 在拥塞发送时如何动作,降低速率
7.2 拥塞感知
发送端如何探测到拥塞?
- 某个段超时了(丢失事件):拥塞
- 超时时间到:某个段的确认没有到来
- 原因1:网络拥塞 (某个路由器缓冲区没空间了,被丢弃)概率大
- 原因2:出错被丢弃了 (各级错误,没有通过校验,被丢弃)概率小
- 一旦超时,就认为拥塞了,有一定误判,但是总体控制方向是对的
- 有关某个段的3次重复ACK:轻微拥塞
- 段的第1个ack,正常,确认绿段,期待红段
- 段的第2个重复ack,意味着红段的后一段收到了,蓝段乱序到达
- 段的第2、3、4个ack重复,意味着红段的后第2、3、4个段收到了 ,橙段乱序到达,同时红段丢失的可能性很大(后面3个段都到了, 红段都没到)
- 网络这时还能够进行一定程度的传输,拥塞但情况要比第一种好
7.3 速率控制方法
如何控制发送端发送的速率
- 维持一个拥塞窗口的值:CongWin(Congestion Window)
- 发送端限制已发送但是未确认 的数据量(的上限):
- LastByteSent-LastByteAcked <= CongWin
- 从而粗略地控制发送方的往网络中注入的速率
- CongWin是动态的,是感知到的网络拥塞程度的函数
- 超时或者3个重复ack,CongWin降低
- 超时时:CongWin 降为1MSS,进入**SS(slow start)**阶段然后再倍增到CongWin / 2(每个RTT),从而进入CA阶段
- 3个重复ack :CongWin降为CongWin / 2,CA阶段
- 否则(正常收到Ack,没有发送以上情况):CongWin跃跃欲试
- SS阶段:加倍增加(每个RTT)
- CA阶段:线性增加(每个RTT)
- 超时或者3个重复ack,CongWin降低
7.4 TCP拥塞控制和流量控制的联合动作
联合控制的方法:
- 发送端控制 发送但是未确认的量 同时也不能够超过接收窗口,满足流量控制要求
- SendWin = min(CongWin, RecvWin)
- 同时满足拥塞控制和流量控制要求
7.4.1 策略概述
拥塞控制策略:
- 慢启动
- AIMD:线性增、乘性减少
- 超时事件后的保守策略
7.4.2 TCP慢启动
-
连接刚建立,CongWin = 1MSS
- 如:MSS=1460bytes & RTT = 200 ms
- 初始速率 = 58.4kbps
-
可用带宽可能 >> MSS / RTT
- 应该尽快加速,到达希望的速率
-
当连接开始时,指数性增加发送速率,知道发生丢失的事件
- 启动初值很低
- 但是速度很快
-
当连接开始时,指数性增加(每个RTT)发送速率直到发生丢失事件
- 每一个RTT,CongWin加倍
- 每收到一个ACK时,CongWin加1
- 慢启动阶段:只要不超时或3个重复ACK,一个RTT,CongWin加倍
-
**总结:**初始速率很慢,但是加速却是指数性的
- 指数增加,SS时间很短,长期来看可以忽略
7.4.3 AIMD(Additive- Increase, Multiplicative- Decrease)
乘性减:
- 丢失事件后将CongWin降为1,将CongWin / 2作为阈值,进入慢启动阶段(倍增直到CongWin / 2)
加性增:
- 当CongWin > 阈值时,一个RTT如果没有发生丢失事件,将CongWin 加 1MSS:探测
- 当收到3个重复的ACKs:
- CongWIn 减半
- 窗口(缓冲区大小)之后线性增长
- 当超时 事件发生时:
- CongWin被设置为1MSS ,进入SS阶段
- 之后窗口指数增长
- 增长到一个阈值(上次发生拥塞的窗口的一半)时,再线性增加
思路
- 3 个重复的ACK表示网络还有一定的段传输能力
- 超时之前的3个重复的ACK表示"警报"
7.4.4 改进
什么时候应该将 指数性增长变成 线性?
在超时之前,当CongWin变成上次发生超时的窗口的一半
实现:
- 变量:Threshold
- 出现丢失,Threshold设置成CongWin的1/2
7.5 总结
- 当 CongWin < Threshold,发送端处于慢启动阶段(slow-start),窗口指数性增长
- 当 CongWin > Threshold,发送端处于拥塞避免阶段(congestion-avoidance),窗口线性增长
- 当 收到三个重复的ACKs(triple,duplicate ACK ),Threshold设置成CongWin/2,CongWin=Threshold+3
- 当 超时事件发生时timeout,Threshold=CongWin/2,CongWin = 1MSS,进入SS阶段
TCP发送端拥塞控制
7.6 TCP吞吐量
- TCP 平均吞吐量是多少,使用窗口window 尺寸W 和RTT 来描述?
- 忽略慢启动阶段,假设发送端总有数据传输
- W :发生丢失事件时的窗口尺寸(单位:字节)
- 平均窗口尺寸(#in-flight字节):3/4W(因为W的变化范围是W/2和W,取均值就是3/4)
- 平均吞吐量:RTT时间吞吐3/4W
7.7 TCP公平性
**公平性目标:**如果K个TCP会话分享一个链路带宽为R的瓶颈,每一个会话的有效带宽为R / K
为什么TCP是公平的?
2个竞争的TCP会话:
- 加性增加,斜率为1,吞吐量增加
- 乘性减,吞吐量比例减少
上图含义:
- 假如我们有两个会话A,B之间竞争带宽,一开始A带宽远大于B
- 我们忽略慢启动阶段,因为增长的太快了
- 那么在加性加阶段,二者每个RTT增加1,也就是斜率为1增长(图中红线)
- 当超过threshold后,各自会被调整到原来的一半,然后再次以斜率为1增长
- ......
- 我们发现每调整一次,二者的差距都会缩小,越来越逼近公平的状态
- 所以,TCP是公平的
公平性和UDP
- 多媒体应用通常不是TCP
- 因为应用发送的数据速率希望不受拥塞控制的影响
- 使用UDP
- 音视频应用泵出数据的速率是恒定的,忽略数据的丢失
- 研究领域:TCP友好性
公平性和并行TCP连接
- 2个主机间可以打开多个并行的TCP连接
- Web浏览器
- 例如:带宽为R 的链路支持了9个连接
- 如果新的应用要求建1个TCP连接,获得带宽R/10
- 如果新的应用要求建立11个连接,那么获得带宽R/2
八、总结
- 传输层提供的服务
- 应用进程间的逻辑通信
- vs 网络层提供的主机到主机的通信服务
- 互联网上传输层协议:UDP、TCP
- 特性
- 应用进程间的逻辑通信
- 多路复用和解复用
- 端口:传输层的SAP
- 无连接的多路复用和解复用
- 面向连接的多路复用和解复用
- 实例1:无连接传输层协议UDP
- 多路复用解复用
- UDP报文格式
- 检错机制:校验和
- 可靠数据传输原理
- 问题描述
- 停止等待协议
- rdt 1.0,2.0,2.1,2.2,3.0
- 流水线协议
- GBN
- SR
- 实例2:面向连接的传输层协议TCP
- 概述:TCP特性
- 报文段格式
- 序号,超时机制及时间
- TCP可靠传输机制
- 重传,快速重传
- 流量控制
- 连接管理
- 三次握手
- 对称连接释放
- 拥塞控制原理
- 网络辅助的拥塞控制(例:ATM)
- 端到端的拥塞控制(例:TCP)
- TCP的拥塞控制
- AIMD
- 慢启动
- 超时之后的保守策略