四、运输层
概述
运输层在五层协议的体系结构的位置
-
从通信和信息处理的角度看,运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。
-
当网络的边缘部分中的两个主机使用网络的核心部分的功能进行端到端的通信时,只有位于网络边缘部分的主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组时都只用到下三层的功能。
作用:
运输层为应用进程之间的通信提供服务。
网络层为主机之间的通信提供服务。
物理层负责处理两个节点 之间的通信
传输层的功能:
-
传输层提供进程和进程之间的逻辑通信。
-
复用和分用
-
传输层对收到的报文进行差错检测。(网络层只检测IP数据包头部)
-
传输层的两种协议
与网络层区别:
网络层是为主机之间提供逻辑通信;运输层为应用进程之间提供端到端的逻辑通信。
TCP 和 UDP协议
TCP/IP 的运输层的两个主要的 运输协议:
- TCP协议
- UDP协议
传输控制协议 TCP (Transmission Control Protocol)
面向连接。如果使用TCP协议,尽管下面的网络是不可靠的(只提供尽最大努力服务),但是逻辑通信信道就相当于一条全双工的可靠信道。
用户数据报协议 UDP (User Datagram Protocol)
无连接,不保证可靠性。此时逻辑通信信道是一条不可靠信道。
运输协议数据单元 TPDU
两个 对等运输实体 在通信时传送的数据单位叫作运输协议数据单元 TPDU (Transport Protocol Data Unit)。
- TCP 传送的数据单位协议是 TCP 报文段(segment)。
- UDP 传送的数据单位协议是 UDP 报文或用户数据报。
所有的 数据包的形式就是不保证可靠性,面向无连接
应用场景:通信时间短,重发对数据影响小采用UDP,否则用TCP。
典型应用
对比
- TCP:可靠,面向连接,时延大,适用 于大文件。
- UDP:不可靠,无连接,时延小,适用 于小文件
端口
运行在计算机中的进程是用 进程标识符 来标志的。
但运行在应用层的各种应用进程却不应当让计算机操作系统指派它的进程标识符。这是因为在互联网上使用的计算机的操作系统种类很多,而不同的操作系统又使用不同格式的进程标识符。
引入目的:
使运行不同操作系统的计算机的应用进程能够互相通信
- 复用:应用层所有的应用进程都可以通过传输层再传输到网络层。
- 分用:传输层从网络层收到数据后交付指明的应用进程。
端口号 (protocol port number)
简称为端口 (port),是应用层和运输层之间通信的标识。
(统一的对 TCP/IP 体系的应用进程进行标志的方法)。
虽然通信的终点是应用进程,但我们可以把端口想象是通信的终点,
因为我们只要把要传送的报文交到目的主机的某一个合适的目的端口,
剩下的工作(即最后交付目的进程)就由 TCP 来完成。
注意:
端口号只具有本地意义,不同计算机的相同端口号是没有联系的。即端口号只是为了标志本计算机应用层中的各进程。
表示
端口用一个 16 位端口号进行标志,允许有65,535个不同的端口号。
分类:两大类,三种
端口号分为两类:
- 服务器端使用的端口号
- 客户端使用的端口号
其中服务器端口又分为:
- 熟知端口,数值一般为 0 ~ 1023。
- 登记端口号,数值为 1024 ~ 49151,为没有熟知端口号的应用程序使用的。
一共三种端口号,下面一一说明:
-
熟知端口
数值一般为 0 ~ 1023。 -
登记端口号
数值为 1024 ~ 49151,为没有熟知端口号的应用程序使用的。 -
客户端使用的端口号
又称为短暂端口号,数值为 49152 ~ 65535,留给客户进程选择暂时使用。
当服务器进程收到客户进程的报文时,就知道了客户进程所使用的动态端口号。通信结束后,这个端口号可供其他客户进程以后使用。
注意:
- 登记端口号 必须在 IANA 登记,以防止重复。
- 实际上多数操作系统会占用登记端口号
常用的熟知端口
在网络中采用发送和接收方的套接字组合来识别端点,套接字唯一标识了网络中的一个主机和它上面的一个进程。
套接字Socket=(主机IP地址,端口号)
UDP协议
UDP 只在 IP 的数据报服务之上增加了两点的功能:
- 复用和分用的功能
- 差错检测的功能
主要特点
-
无连接
发送数据之前不需要建立连接,因此减少了开销和发送数据之前的时延。 -
不保证可靠交付,尽最大努力交付
因此主机不需要维持复杂的连接状态表。 -
没有拥塞控制
因此网络出现的拥塞不会使源主机的发送速率降低。这对某些实时应用是很重要的。很适合多媒体通信的要求。
因此网络流量小,正常工作时UDP速度快。但是当网络拥堵时,UDP效率低。
-
UDP 支持一对一、一对多、多对一和多对多的交互通信。
-
UDP 的首部开销小
只有 8 个字节,比 TCP 的 20 个字节的首部要短。 -
面向报文。
UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。UDP 一次交付一个完整的报文。
应用场景
- 通信时间短
- 要求速度快,但是对可靠性要求不高。
UDP报文
UDP 的首部格式
用户数据报 UDP 有两个字段:数据字段和首部字段。
首部字段有 8 个字节,由 4 个字段组成,每个字段都是 2 个字节。
UDP的校验
“伪首部”(伪首部 伪的是IP数据报的首部)
在计算检验和时,临时把 12 字节的“伪首部”和 UDP 用户数据报连接在一起。
(17指使用的UDP协议)
注
- 检验和把首部和数据部分一起都检验。
- 伪首部仅仅是为了计算检验和,不进行传输。
检验和计算: 按二进制反码运算求和,将得出的结果求反码
-
在发送端的时候:
1.就是将每一行(4字节)拆成两部分,左右平均2字节大小,将这两字节数据写成二进制,那么2字节一共就需要\(2×8=16\) 位。此时检验和没有计算,默认填充0,同时如果数据字段不整齐,则用0补齐,这样就可以写出几十行二进制数,如图中方所示
2.计算着几十行二进制数按二进制反码运算求和,二进制反码运算可以参考
二进制反码求和运算
得到的最后简介再反码,之后将反码之后的放入原来的检验和字段 -
在接收端的时候(
与在发送端不同,此时检验和字段不是0了
)
按照发送端的步骤再将所有数据写成二进制进行二进制反码运算求和
如果最后得到结果全1就是没问题,否则丢弃
TCP协议
主要特点
-
面向连接
虚连接
在无连接的、不可靠的 IP 网络服务基础之上提供可靠交付的服务。
为此,在 IP 的数据报服务基础之上,增加了保证可靠性的一系列措施。 -
提供可靠交付
-
有拥塞控制
-
只支持一对一通信
每一条 TCP 连接只能有两个端点 (endpoint),每一条 TCP 连接只能是点对点的(一对一)。 -
TCP 提供全双工通信。
-
面向字节流
TCP 中的“流”(stream) 指的是流入或流出进程的字节序列。
\(\to\) TCP把应用程序交下来的数据看成仅仅是一连串的无结构的字节流。
面向字节流
含义: 虽然应用程序和 TCP 的交互是一次一个数据块,但 TCP 把应用程序交下来的数据看成仅仅是一连串无结构的字节流。
理解:
-
TCP 不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系。
-
但保证接收方应用程序收到的字节流和发送方应用程序发出的字节流完全一样。
也就是说:
TCP 不关心应用进程一次把多长的报文发送到 TCP 缓存。
TCP 对连续的字节流进行分段,形成 TCP 报文段。
过程
发送方:
- 发送数据,TCP 将数据缓存
- 缓存到设定值,将数据缓存发送
接收方:
- 边接受,应用程序边读取。
- 读取成功后,接收方删除缓存;
- 向发送方发送确认信息
发送方:
- 删除该缓存
注 意
TCP 根据对方给出的窗口值和当前网络拥塞的程度来决定一个报文段应包含多少个字节(UDP 发送的报文长度是应用进程给出的)。
- TCP 可把太长的数据块划分短一些再传送。
- TCP 也可等待积累有足够多的字节后再构成报文段发送出去。
面向连接
TCP 把连接作为最基本的抽象。
套接字 (socket)
套接字 (socket)
TCP 连接的端点 叫做套接字 (socket) 或插口。
每一条 TCP 连接有两个端点。
组成:套接字 socket = (IP地址 : 端口号)
例:
套接字 socket = (192.169.1.20 : 2028)
作用:
两个套接字唯一的确定TCP连接。
也就是说:每一条 TCP 连接唯一地被通信两端的两个端点(即两个套接字)所确定。
即:
TCP 连接 ::= {socket1, socket2}
= {(IP1: port1),(IP2: port2)}
TCP 连接,IP 地址,套接字三者关系
TCP 连接就是由协议软件所提供的一种抽象。
TCP 连接的端点是个很抽象的套接字,即(IP 地址:端口号)。
- 同一个 IP 地址可以有多个不同的 TCP 连接。
- 同一个端口号也可以出现在多个不同的 TCP 连接中。
TCP 报文段的首部格式
TCP 虽然是面向字节流的,但 TCP 传送的数据单元却是报文段。
一个 TCP 报文段分为首部和数据两部分,而 TCP 的全部功能都体现在它首部中各字段的作用。
TCP 报文段首部的前 20 个字节是固定的,后面有 4n 字节是根据需要而增加的选项 (n 是整数)。因此 TCP 首部的最小长度是 20 字节。
源端口和目的端口字段
——各占 2 字节。端口是运输层与应用层的服务接口。运输层的复用和分用功能都要通过端口才能实现。
序号字段seq
——占 4 字节。TCP 连接中传送的数据流中的每一个字节都编上一个序号。
序号字段的值则指的是本报文段所发送的数据的第一个字节的序号。
例如:
现有5000个字节的数据。
假设报文段的最大数据长度为1000个字节,初始序号为1001。
报文段 1 序号 = 1001 (数据字节序号:1001 ~ 2000)
报文段 2 序号 = 2001 (数据字节序号:2001 ~ 3000)
报文段 3 序号 = 3001 (数据字节序号:3001 ~ 4000)
报文段 4 序号 = 4001 (数据字节序号:4001 ~ 5000)
报文段 5 序号 = 5001 (数据字节序号:5001 ~ 6000)
确认号字段ack
——占 4 字节,是期望收到对方的下一个报文段的数据的第一个字节的序号。
也就是已经正确收到的报文的最后一个字节的序号+1
。
数据偏移(即首部长度)
——占 4 位,它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。“数据偏移”的单位是 32 位字(以 4 字节为计算单位)。
(最小5,最大60)
保留字段
——占 6 位,保留为今后使用,但目前应置为 0。
控制位:6个
紧急 URG
—— 当 URG = 1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。
确认 ACK
—— 只有当 ACK =1 时确认号字段才有效。当 ACK =0 时,确认号无效。
推送 PSH (PuSH)
—— 接收 TCP 收到 PSH = 1 的报文段,就尽快地交付接收应用进程,而不再等到整个缓存都填满了后再向上交付。
尽快交付和URG的尽快传送不同。
尽快交付:接收后,接收端尽快的提交缓存。
尽快传送:发送端尽快发送。
复位 RST (ReSeT)
当 RST=1 时,表明 TCP 连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。
一般用于拒绝连接请求,
同步 SYN
同步 SYN = 1 表示这是一个连接请求或连接接受报文。
- SYN=1,ACK=0:请求连接报文。
- SYN=1,ACK=1:连接接受报文。
终止 FIN (FINish)
用来释放一个连接。FIN=1 表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。
窗口字段(接收窗口)
占 2 字节,接收方 用来通知 发送方设置发送窗口 的依据,单位为字节。
注意:
- 窗口字段是接收方的接收窗口大小。
- 因为接收窗口限制发送窗口的大小。因此窗口字段是 发送方设置发送窗口大小的依据。
窗口值经常动态变化。
检验和
—— 占 2 字节。检验和字段检验的范围包括首部和数据这两部分。在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部。
在计算检验和时,临时把 12 字节的“伪首部”和 TCP 报文段连接在一起。伪首部仅仅是为了计算检验和。
紧急指针字段
—— 占 16 位,指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)。
选项字段
—— 长度可变。TCP 最初只规定了一种选项,即最大报文段长度 MSS。
注意:选项字段没有使用或者使用部分字段 ,要用0填充
MSS (Maximum Segment Size)
MSS 告诉对方 TCP:“我的缓存所能接收的报文段的数据字段的最大长度是 MSS 个字节。”
是 TCP 报文段中的数据字段的最大长度。
数据字段加上 TCP 首部才等于整个的 TCP 报文段。
所以,MSS是“TCP 报文段长度减去 TCP 首部长度”。
为什么要规定 MSS ?
- MSS 与接收窗口值没有关系。
- 若选择较小的 MSS 长度,网络的利用率就降低。
- 若 TCP 报文段非常长,那么在 IP 层传输时就有可能要分解成多个短数据报片。在终点要把收到的各个短数据报片装配成原来的 TCP 报文段。当传输出错时还要进行重传。这些也都会使开销增大。
- 因此,MSS 应尽可能大些,只要在 IP 层传输时不需要再分片就行。
- 最佳的 MSS 是很难确定的。
其他选项
-
窗口扩大选项 ——占 3 字节,其中有一个字节表示移位值 S。新的窗口值等于 TCP 首部中的窗口位数增大到 (16 + S),相当于把窗口值向左移动 S 位后获得实际的窗口大小。
最多14位。 -
时间戳选项——占 10 字节,其中最主要的字段时间戳值字段(4 字节)和时间戳回送回答字段(4 字节)。
-
选择确认选项——在后面的 5.6.3 节介绍。
填充字段
这是为了使整个首部长度是 4 字节的整数倍。
TCP连接管理
TCP 是面向连接的协议。TCP 连接有三个阶段:
- 连接建立
- 数据传送
- 连接释放
TCP 连接的管理就是使 TCP 连接的建立和释放都能正常地进行。
TCP 连接建立过程中要解决的三个问题
- 要使每一方能够确知对方的存在。
- 要允许双方协商一些参数(如最大窗口值、是否使用窗口扩大选项和时间戳选项以及服务质量等)。
- 能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配。
TCP 连接的建立采用客户服务器方式。
- 主动发起连接建立的应用进程叫做客户 (client)。
- 被动等待连接建立的应用进程叫做服务器 (server)。
TCP 的连接建立
TCP 建立连接的过程叫做握手。
握手需要在客户和服务器之间交换三个 TCP 报文段。称之为三报文握手。
采用三报文握手主要是为了防止已失效的连接请求报文段突然又传送到了,因而产生错误。
-
ROUND 1:
SYN=1, seq=x(随机)
客户端发送连接请求报文段,无应用层数据。 -
ROUND 2:
SYN=1,ACK=1,seq=y(随机),ack=x+1
服务器端为该TCP连接分配缓存和变量,并向 客户端返回确认报文段,允许连接,无应用层数据。 -
ROUND 3:
SYN=0,ACK=1, seq=x+1, ack=y+1
客户端为该TCP连接分配缓存和变量,并向服 务器端返回确认的确认,可以携带数据。
TCP三次握手特定导致的SYN洪泛攻击
SYN:同步序号,用于建立连接过程,在连接请求中,SYN=1和ACK=0表示该数据段没有使用捎带的确认域,而连接应答捎带一个确认,即SYN=1和ACK=1
FIN:用于释放连接,为1时表示发送方没有发送了
ACK:为1表示确认号有效,为0表示报文不含确认信息,忽略确认号字段,上面的确认号是否有效就是通过该标识控制的
ack:是期望收到对方下一个报文段的第一个数据字节的序号
seq:TCP连接中传送的字节流中的每个字节都按顺序编号
TCP连接释放(四次挥手)
参与一条TCP连接的两个进程中的任何一个都能终止该连接,连接结束后,主机中的“资源”(缓存和变量)将被释放。
-
ROUND 1:
FIN=1, seq=u
客户端发送连接释放报文段,停止发送数据,主动 关闭TCP连接。 -
ROUND 2:
ACK=1, seq=v, ack=u+1
服务器端回送一个确认报文段,客户到服务器这个 方向的连接就释放了——关闭状态。 -
ROUND 3:
FIN=1,ACK=1, seq=w, ack=u+1
服务器端发完数据,就发出连接释放报文段,主动 关闭TCP连接。 -
ROUND 4:
ACK=1, seq=u+1, ack=w+1
客户端回送一个确认报文段,再等到时间等待计时 器设置的2MSL(最长报文段寿命)后,连接彻底关闭。
为什么需要等待计时2MSL?
因为这样可以保证B可以收到A的终止报文段进而进入关闭状态
比如说如果A的第四段报文丢失,那么等待一个MSL之后B就会重传第三段报文,花费小于1MSL之后A就会再收到第三段报文,之后就可以再次向B发送第四段报文提示B关闭连接
可靠传输
可靠:保证接收方进程从缓存区读出的字节流与发送方发出的字节流是完全一样的。
理想的传输条件:
- 传输信道不产生差错。
- 不管发送方以多快的速度发送数据,接收方总是来得及接收和处理收到的数据。
在这样的理想传输条件下,不需要采取任何措施就能够实现可靠传输。
然而实际的网络都不具备以上两个理想条件。必须使用一些可靠传输协议,在不可靠的传输信道实现可靠传输。
TCP实现可靠传输的机制
1.校验(差错检测) ;2.序号;3.确认;4.重传
自动重传请求 ARQ
自动重传请求(Automatic Repeat-reQuest,ARQ)是数据链路层和传输层的错误纠正协议之一。
作用: 它通过使用确认和重传机制,在不可靠服务的基础上实现可靠的信息传输。
实现:
如果发送方在发送后一段时间之内没有收到确认帧,就自动重发。
注意:
重传的请求是自动进行的,接收方不需要请求发送方重传某个出错的分组。
超时重传和编号
原因:
为了实现可靠传输,必须实现重传。
为了避免重传带来的冲突,必须对报文进行编号。
超时重传: 每一个已发送的分组都设置了一个超时计时器,如果时间段内未收到确认报文,自动重新发送该报文。
编号: 对每个发送报文 和 确认报文 进行编号
ARQ分类:
- 停止等待ARQ协议
- 连续ARQ协议
停止等待ARQ协议
“停止等待”就是每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。
协议要点
- 停止等待。发送方每次只发送一个分组。在收到确认后再发送下一个分组。
- 编号。对发送分组和确认分组都进行编号。
- 自动重传请求。发送方为每个发送的分组设置一个超时计时器。若超时计时器超时,发送方会自动重传分组。
优点:简单
缺点:信道利用率太低。
注意
- 在发送完一个分组后,必须暂时保留已发送的分组的副本,以备重发。
- 超时计时器的重传时间应当比数据在分组传输的平均往返时间更长一些。
下面通过不同的情况,来分析为什么需要编号和重传机制:
注意: 全双工通信的双方既是发送方也是接收方。
为了讨论问题的方便 ,我们仅考虑 A 发送数据,而 B 接收数据并发送确认。因此 A 叫做发送方,而 B 叫做接收方。
无差错情况
A 发送分组 M1,发完就暂停发送,等待 B 的确认 (ACK)。
B 收到了 M1 向 A 发送 ACK。
A 在收到了对 M1 的确认后,就再发送下一个分组 M2。
分组错误和分组丢失
解决方法:超时重传
接收方B处理方法:丢弃分组,不发送任何信息。
- 分组丢失:B 接收 M1 时检测出了差错,就丢弃 M1,其他什么也不做(不通知 A 收到有差错的分组)。
- 分组重传:M1 在传输过程中丢失了,这时 B 当然什么都不知道,也什么都不做。
A如何知道 B 是否正确收到了 M1 呢?
发送方A处理方法:超时重传
发送方A 为每一个已发送的分组都设置了一个超时计时器。
- A 只要在超时计时器到期之前收到了相应的确认,就撤销该超时计时器,继续发送下一个分组 M2 。
- 若A在超时计时器规定时间内没有收到B的确认,就认为分组错误或丢失,就重发该分组。
确认丢失和确认迟到
问题:
确认丢失:若 B 所发送的对 M1 的确认丢失了,那么 A 在设定的超时重传时间内不能收到确认。
确认迟到: 传输过程中没有出现差错,但 B 对分组 M1 的确认迟到了。
解决方法:编号
发送方A为每一个发送的分组都进行编号。
接受方B为发送的确认也进行编号,指示该确认是对哪一个分组的确认。
确认丢失 解决过程:
因为 A 无法知道:是自己发送的分组出错、丢失了,或者 是 B 发送的确认丢失了。
发送方A 在超时计时器到期后,重传 M1。
假定 B 又收到了重传的分组 M1。
接收方B :
- 丢弃这个重复的分组 M1,不向上层交付。
- 向 A 发送确认。
不能认为已经发送过确认就不再发送,因为 A 之所以重传 M1 就表示 A 没有收到对 M1 的确认。
确认迟到 解决过程:
发送方A 在超时计时器到期后,重传 M1。
接收方B 会收到重复的 M1,因此要:
- 并且同样要丢弃重复的 M1
- 重传确认分组。
发送方A收到重复的确认,直接丢弃。
可以看到在有确认机制中每个报文必须有序号。比如说:如果没有对于确认迟到时:A会认为迟到的确认报文是 M2的确认报文。
信道利用率
信道:一般用来表示向某一个方向传送信息的媒体。
(信道有方向,只有传输信息时才能叫信道)
停止等待ARQ 信道利用情况:
设:\(RTT\):发送时间;\(T_D\):分组发送时间;\(T_A\):确认时间,则信道利用率U
可以看出,当往返时间 \(RTT\) 远大于分组发送时间 \(T_D\) 时,信道的利用率就会非常低。
若出现重传,则对传送有用的数据信息来说,信道的利用率就还要降低。
因此
停止等待协议的优点是简单,缺点是信道利用率太低。
流水线传输
为了提高传输效率,发送方可以不使用低效率的停止等待协议,而是采用流水线传输。
流水线传输就是发送方可连续发送多个分组,不必每发完一个分组就停顿下来等待对方的确认。这样可使信道上一直有数据不间断地传送。
由于信道上一直有数据不间断地传送,这种传输方式可获得很高的信道利用率。。
很明显流水线的 发送能力(发送窗口及大小) 受到两方面限制:
- 接收端的接收能力(接受窗口大小:接收缓冲空闲的大小)
- 网络的传输能力(拥塞窗口大小)
也就是说: \(发送能力=min(接收能力,网络传输能力)\)
考虑发送能力和接收能力:流量控制
考虑发送能力和网络传输能力:拥塞控制
发送窗口大小和接受窗口大小:滑动窗口机制
连续 ARQ 协议
基本思想:
- 发送方一次可以发出多个分组。
- 使用滑动窗口协议控制发送方和接收方所能发送和接收的分组的数量和编号。
- 每收到一个确认,发送方就把发送窗口向前滑动。
- 接收方一般采用累积确认的方式。
- 采用回退N(Go-Back-N)方法进行重传。
滑动窗口协议
滑动窗口协议比较复杂,是 TCP 协议的精髓所在。
目的: 减少确认次数,提高信道利用率
发送方维持的发送窗口:
允许发送的分组数量,只能发送发送窗口的分组。
而且位于发送窗口内的分组都可连续发送出去,而不需要等待对方的确认。
发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置。
接收方维持的接收窗口:
允许接收的分组数量
实现过程:
发送后,在收到确认前,发送窗口会变小
接收的分组正确,向前滑动接收窗口
收到确认后,向前滑动发送窗口,窗口变大
累积确认
接收方一般采用累积确认的方式。即不必对收到的分组逐个发送确认,而是对按序到达的最后一个分组发送确认,这样就表示:到这个分组为止的所有分组都已正确收到了。
也就是说:发送\(ACK_4\)意味着前四个都确认成功。
优点:容易实现,即使确认丢失也不必重传。
缺点:不能向发送方反映出接收方已经正确收到的所有分组的信息。
Go-back-N(回退 N)
如果发送方发送了前 5 个分组,而中间的第 3 个分组丢失了。这时接收方只能对前两个分组发出确认。发送方无法知道后面三个分组的下落,而只好把后面的三个分组都再重传一次。
这就叫做 Go-back-N(回退 N),表示需要再退回来重传已发送过的 N 个分组。
可见当通信线路质量不好时,连续 ARQ 协议会带来负面的影响。
TCP 可靠通信的实现
- TCP 连接的每一端都必须设有两个窗口——一个发送窗口和一个接收窗口。,共4个窗口
- TCP 的可靠传输机制用字节的序号进行控制。TCP 所有的确认都是基于序号而不是基于报文段。
- TCP 两端的四个窗口经常处于动态变化之中。
- TCP连接的往返时间 RTT 也不是固定不变的。需要使用特定的算法估算较为合理的重传时间。
以字节为单位的滑动窗口
TCP 使用流水线传输和滑动窗口协议实现高效、可靠的传输。
TCP 的滑动窗口是以字节为单位的。
发送方 A 和接收方 B 分别维持一个发送窗口和一个接收窗口。
- 发送窗口表示:在没有收到确认的情况下,可以连续把窗口内的数据全部发送出去。
- 接收窗口表示:只允许接收落入窗口内的数据。
发送窗口和接收窗口
1. 根据 B 给出的窗口值,A 构造出自己的发送窗口
- 发送窗口表示:在没有收到 B 的确认的情况下,A 可以连续把窗口内的数据都发送出去。
- 发送窗口里面的序号表示允许发送的序号。
注:
- TCP 标准强烈不赞成 发送窗口前沿向后收缩
- 显然,窗口越大,发送方就可以在收到对方确认之前连续发送更多的数据,因而可能获得更高的传输效率。
2. A 发送了 11 个字节的数据
-
A 的发送窗口位置不变,但是
可用窗口
变小
P3 – P1 = A 的发送窗口(又称为通知窗口)
P2 – P1 = 已发送但尚未收到确认的字节数
P3 – P2 = 允许发送但尚未发送的字节数(可用窗口) -
B的接收窗口,有数据未按序到达,B先存下,等待缺少的数据的到达
-
若B收到数据,且未到达数据不在后沿,则B的接收窗口向前滑动
3. A 收到新的确认号,发送窗口向前滑动
4. A 的发送窗口内的序号都已用完,但还没有再收到确认,必须停止发送。
发送缓存
发送缓存用来暂时存放:
- 发送应用程序传送给发送方 TCP 准备发送的数据;
- TCP 已发送出但尚未收到确认的数据。
注:发送窗口通常只是发送缓存的一部分。
接收缓存
接收方的应用进程从 TCP 的接收缓存中读取字节流。
接收缓存用来暂时存放:
- 按序到达的、但尚未被接收应用程序读取的数据;
- 不按序到达的数据。
超时重传时间的选择(不考)
超时重传
TCP 每发送一个报文段,就对这个报文段设置一次计时器。
只要计时器设置的重传时间到但还没有收到确认,就要重传这一报文段。
TCP 超时重传时间设置
重传时间的选择是 TCP 最复杂的问题之一。
如果把超时重传时间设置得太短,就会引起很多报文段的不必要的重传,使网络负荷增大。
但若把超时重传时间设置得过长,则又使网络的空闲时间增大,降低了传输效率。
TCP 采用了一种自适应算法:
它记录一个报文段发出的时间戳,以及收到相应的确认的时间戳。这两个时间之差就是报文段的往返时间 RTT。
(一)加权平均往返时间\(RTT_S\)
TCP保留了RTT的一个加权平均往返时间\(RTT_S\)(又称为平滑的往返时间)。
第一次测量到 RTT 样本时,RTTS 值就取为所测量到的 RTT 样本值。
以后每测量到一个新的 RTT 样本,就按下式重新计算一次 RTTS:
\(新的RTT_S = (1 - a) × (旧的RTTS) + a × (新的RTT样本)\)
\(0 ≤ a <1\)。
若 \(a\) 很接近于零,表示 \(RTT_s\) 值更新较慢。
若选择 \(a\) 接近于 1,则表示 \(RTT_s\) 值更新较快。
RFC 6298 推荐的 \(a\) 值为 1/8,即 0.125。
(二)超时重传时间 RTO
RTO (Retransmission Time-Out) 应略大于上面得出的加权平均往返时间 RTTS。
lRFC 6298 建议使用下式计算 RTO:
\(RTO = RTT_S + 4 × RTT_D\)
- \(RTT_D\) 是 RTT 的偏差的加权平均值。
RFC 6298 建议这样计算\(RTT_D\) 。
第一次测量时, RTTD 值取为测量到的 RTT 样本值的一半。
在以后的测量中,则使用下式计算加权平均的 RTTD :
\(新的 RTT_D = (1 - \beta ) × (旧的RTT_D) + \beta × |RTT_S - 新的 RTT 样本|\)
- b是个小于 1 的系数,其推荐值是 1/4,即 0.25。
(三)、往返时间 (RTT) 的测量
问题:
TCP 报文段 1 没有收到确认。重传(即报文段 2)后,收到了确认报文段 ACK。
如何判定此确认报文段是对原来的报文段 1 的确认,还是对重传的报文段 2 的确认?
(三、1)Karn 算法
在计算平均往返时间 RTT 时,只要报文段重传了,就不采用其往返时间样本。
这样得出的加权平均平均往返时间 RTTS 和超时重传时间 RTO 就较准确。
但是,这又引起新的问题。
当报文段的时延突然增大了很多时,在原来得出的重传时间内,不会收到确认报文段。于是就重传报文段。但根据 Karn 算法,不考虑重传的报文段的往返时间样本。
这样,超时重传时间就无法更新。
(三、2)修正的 Karn 算法
报文段每重传一次,就把 RTO 增大一些:
\(新的 RTO = \gamma × (旧的 RTO)\)
- 系数 \(\gamma\) 的典型值是 2 。
当不再发生报文段的重传时,才根据报文段的往返时延更新平均往返时延 RTT 和超时重传时间 RTO 的数值。
实践证明,这种策略较为合理。
选择确认 SACK
问题:若收到的报文段无差错,只是未按序号,中间还缺少一些序号的数据,那么能否设法只传送缺少的数据而不重传已经正确到达接收方的数据?
解决方法: 选择确认 SACK (Selective ACK)
实现过程:
-
在建立 TCP 连接时,就要在 TCP 首部的选项字段中加上“允许 SACK”的选项。
(双方必须都事先商定好。) -
在 TCP 报文段的首部中都增加了 SACK 选项(左右边界),以便报告收到的不连续的字节块的边界。
注意:
左边界指出字节块的第一个字节的序号,但右边界减 1 才是字节块中的最后一个序号。
例子:
前后字节不连续的每一个字节块都有两个边界:边界和右边界。
- 第一个字节块的左边界 L1 = 1501,但右边界 R1 = 3001。
- 第二个字节块的左边界 L2 = 3501,而右边界 R2 = 4501。
注意:
-
在选项中最多只能指明 4 个字节块的边界信息。
由于首部选项的长度最多只有 40 字节,而指明一个边界就要用掉 4 字节 -
由操作系统和程序员选择是SACK还是go back N。
TCP流量控制(滑动窗口)
问题: 一般说来,我们总是希望数据传输得更快一些。但如果发送方把数据发送得过快,接收方就可能来不及接收,这就会造成数据的丢失。
流量控制 (flow control)
就是让发送方的发送速率不要太快,既要让接收方来得及接收,也不要使网络发生拥塞。
实现:
利用滑动窗口机制:
- 接收方 先告诉 发送方 接收窗口大小。
- 发送方按照接收窗口大小设置发送窗口大小。
利用可变窗口进行流量控制举例
A 向 B 发送数据。在连接建立时,B 告诉 A:“我的接收窗口 rwnd = 400(字节)”。且设序号初始值为1,一个报文段100B
(红字部分就是流量控制)
持续计时器
解决的问题 :0接受窗口 死锁
- B 向 A 发送了零窗口的报文段后不久,B 的接收缓存又有了一些存储空间。于是 B 向 A 发送了 rwnd = 400 的报文段。
- 但这个报文段在传送过程中丢失了。
- A 一直等待收到 B 发送的非零窗口的通知,而 B 也一直等待 A 发送的数据。
如果没有其他措施,这种互相等待的死锁局面将一直延续下去。
为了解决该问题,TCP 为每一个连接设有一个持续计时器 (persistence timer)。
- 只要 TCP 连接的一方收到对方的零窗口通知,就启动该持续计时器。
- 若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅携带 1 字节的数据),而对方就在确认这个探测报文段时给出了现在的窗口值。
若窗口仍然是零,则收到这个报文段的一方就重新设置持续计时器。
若窗口不是零,则死锁的僵局就可以打破了。
TCP 的传输效率
TCP的传输效率主要来自TCP 报文段的发送时机。
TCP 报文段的发送时机的不同机制:
-
第一种机制是 TCP 维持一个变量,它等于最大报文段长度 MSS。只要缓存中存放的数据达到 MSS 字节时,就组装成一个 TCP 报文段发送出去。
-
第二种机制是由发送方的应用进程指明要求发送报文段,即 TCP 支持的推送 (push) 操作。
-
第三种机制是发送方的一个计时器期限到了,这时就把当前已有的缓存数据装入报文段(但长度不能超过 MSS)发送出去。
如何控制 TCP 发送报文段的时机仍然是一个较为复杂的问题。
TCP 的拥塞控制
TCP 的有限状态机
箭头旁边的字,表明引起这种变迁的原因,或表明发生状态变迁后又出现什么动作。
图中有三种不同的箭头。
粗实线箭头表示对客户进程的正常变迁。
粗虚线箭头表示对服务器进程的正常变迁。
细线箭头表示异常变迁。