传输层协议概述
进程间通信
运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。
当网络的边缘部分中的两个主机使用网络的核心部分的功能进行端到端的通信时,只有位于网络边缘部分的主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组时都只用到下三层的功能。
网络层只把分组发送到目的主机,但是真正通信的并不是主机而是主机中的进程。传输层提供了进程间的逻辑通信,传输层向高层用户屏蔽了下面网络层的核心细节,使应用程序看起来像是在两个传输层实体之间有一条端到端的逻辑通信信道。
网络层和运输层的区别:网络层是为主机之间提供逻辑通信,而运输层为应用进程之间提供端到端的逻辑通信。见下图。
在一台主机中经常有多个应用进程同时分别和另一台主机中的多个应用进程通信。 这表明运输层有一个很重要的功能——复用(multiplexing)和分用 (demultiplexing)。
运输层还需要对收到的报文进行差错检测。
传输层的两个协议
根据应用程序的不同需求,传输层需要有两种不同的运输协议,即面向连接的 TCP 和无连接的 UDP 。
用户数据报协议 UDP(User Datagram Protocol)是无连接的,使用的是不可靠信道。尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加 UDP 首部),支持一对一、一对多、多对一和多对多的交互通信。UDP用户数据报。
传输控制协议 TCP(Transmission Control Protocol)是面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块),每一条 TCP 连接只能是点对点的(一对一)。TCP 报文段。
使用 UDP 或 TCP 协议的应用层协议
应用 |
应用层协议 |
传输层协议 |
---|---|---|
名字转换 |
DNS(域名系统) |
UDP |
文件传输 |
TFTP(简单文件传送协议) |
UDP |
路由选择协议 |
RIP(路由信息协议) |
UDP |
IP 地址配置 |
DHCP(动态主机配置协议) |
UDP |
网络管理 |
SNMP(简单网络管理协议) |
UDP |
远程文件服务器 |
NFS(网络文件系统) |
UDP |
IP 电话 |
专用协议 |
UDP |
流式多媒体通信 |
专用协议 |
UDP |
多播 |
IGMP(网际组管理协议) |
UDP |
电子邮件 |
SMTP(简单邮件传送协议) |
TCP |
远程终端接入 |
TELENT(远程终端协议) |
TCP |
万维网 |
HTTP(超文本传输协议) |
TCP |
文件传输 |
FTP(文件传送协议) |
TCP |
传输层的端口
端口用一个 16 位端口号进行标志,允许 65535 个不同端口。 端口号只具有本地意义,即端口号只是为了标识本计算机应用层中的各进程。 在互联网中,不同计算机的相同端口号是没有联系的。
由此可见,两个计算机中的进程要互相通信,不仅必须知道对方的 IP 地址(为了找到对方的计算机),而且还要知道对方的端口号(为了找到对方计算机中的应用进程)。
端口分为服务器端使用的和客户端使用的,常用的熟知端口(服务器端):
用户数据报协议UDP
概述
用户数据协议 UDP 是无连接的,它在 IP 层的数据报服务上只增加了:复用和分用的功能、差错检测的功能。
当运输层从 IP 层收到 UDP 数据报时,就根据首部中的目的端口,把 UDP 数据报通过相应的端口,上交最后的终点:应用进程。
如果接收方 UDP 发现收到的报文中的目的端口不正确(即不存在对应端口的进程),就丢弃该报文,并由
网际控制报文协议 ICMP发送“端口不可达”差错报文给发送方!!
请注意,虽然在 UDP 之间的通信要用到其端口号,但由于 UDP 的通信是无连接的,因此不需要使用套接字。
UDP协议的首部格式
用户数据报 UDP 有两个字段:数据字段和首部字段。首部字段很简单,只有 8 个字节。四个字段的长度都是 2 字节。
源端口:需要对方回信时使用,不需要时可用全 0。
目的端口
长度:UDP 数据报的长度,最小值是仅有首部时的 8。
校验和:检验传输是否出错,出错丢弃。UDP 的校验和是把首部和数据部分一起校验。12 字节的伪首部是为了计算检验和临时添加的。
UDP协议特点
(1) UDP 是无连接的,发送数据之前不需要建立连接,因此减少了开销和发送数据之前的时延。
(2) UDP 使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态表。
(3) UDP 是面向报文的。UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。UDP 一次交付一个完整的报文。 如下图。
(4) UDP 没有拥塞控制,因此网络出现的拥塞不会使源主机的发送速率降低。这对某些实时应用是很重要的。很适合多媒体通信的要求。
(5) UDP 支持一对一、一对多、多对一和多对多的交互通信。
(6) UDP 的首部开销小,只有 8 个字节,比 TCP 的 20 个字节的首部要短。
传输控制协议TCP
概述
特点:传输控制协议TCP是面向连接的运输层协议,每一条 TCP 连接只能有两个端点 (endpoint),每一条 TCP 连接只能是点对点的(一对一)。 TCP 提供可靠交付的服务。 TCP 提供全双工通信、面向字节流(TCP 中的“流”(stream)指的是流入或流出进程的字节序列。 “面向字节流”的含义是:虽然应用程序和 TCP 的交互是一次一个数据块,但 TCP 把应用程序交下来的数据看成仅仅是一连串无结构的字节流。 ) 如下图。
TCP 连接是一条虚连接而不是一条真正的物理连接。TCP 根据对方给出的窗口值和当前网络拥塞的程度来决定一个报文段应包含多少个字节(UDP 发送的报文长度是应用进程给出的)。
TCP 并不关心应用进程一次把多长的报文发送到 TCP 的缓存中,而是根据对方给出的窗口值和当前网络拥塞的程序来决定一个报文段应该包含多少个字节。如果缓存的数据块太长可以划分短一些再传送。
TCP的连接:每一条 TCP 连接有 2 个端点,TCP 连接的端点叫做套接字 (socket) 或插口。 端口号拼接到 (contatenated with) IP 地址即构成了套接字。
套接字 socket = (IP地址 : 端口号)
每一条 TCP 连接唯一地被通信两端的两个端点(即两个套接字)所确定。即:
同一个 IP 地址可以有多个不同的 TCP 连接,而同一个端口号也可以出现在多个不同的 TCP 连接中。
TCP 为了实现和其他协议的不同:可靠传输。需要一些特定的功能:停止等待协议、连续 ARQ 协议 、滑动窗口协议(TCP协议的精髓)。
TCP报文的首部格式
TCP 虽然是面向字节流的,但 TCP 传送的数据单元却是报文段。
一个 TCP 报文段分为首部和数据两部分,而 TCP 的全部功能都体现在它首部中各字段的作用。TCP 报文作为 IP 数据报的数据部分。
TCP 报文段首部的前 20 个字节是固定的,后面有 4N 字节是根据需要而增加的选项 (N 是整数)。因此 TCP 首部的最小长度是 20 字节。
源端口和目的端口:各占 2 字节。端口是运输层与应用层的服务接口。运输层的复用和分用功能都要通过端口才能实现。
序号 seq :占 4 字节。TCP 连接中传送的数据流中的每一个字节都编上一个序号。序号字段的值则指的是本报文段所发送的数据的第一个字节的序号。
确认号 ack:占 4 字节,是期望收到对方的下一个报文段的数据的第一个字节的序号。
若确认号ack = N,则表明:到序号 N - 1 为止的所有数据都已正确收到
数据偏移:即首部长度。占 4 位,它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。“数据偏移”的单位是 32 位字(以 4 字节为计算单位)。
保留:占 6 位,保留为今后使用,但目前应置为 0。
紧急 URG:当 URG = 1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。
确认 ACK 标志位:只有当 ACK = 1 时确认号字段才有效。当 ACK = 0 时,确认号无效。
推送 PSH:接收 TCP 收到 PSH = 1 的报文段,就尽快地交付接收应用进程,而不再等到整个缓存都填满了后再向上交付。
复位 RST:当 RST = 1 时,表明 TCP 连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。
同步 SYN 标志位:(Synchronize Sequence Numbers)同步 SYN = 1 表示这是一个连接请求或连接接受报文。在连接时用来同步序号。
终止 FIN 标志位:用来释放一个连接。FIN = 1 表明此报文段的发送端的数据已发送完毕,并要求释放连接。
窗口:占 2 字节,用来让对方设置发送窗口的依据,单位为字节。窗口字段明确指出了现在允许对方发送的数据量,窗口值常在动态变化着。
校验和:占 2 字节。检验和字段检验的范围包括首部和数据这两部分。在计算检验和时,临时在 TCP 报文段的前面加上 12 字节的伪首部。
紧急指针字段:占 16 位,指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)。
选项:长度可变。TCP 最初只规定了一种选项,即最大报文段长度 MSS。MSS 告诉对方 TCP:“我的缓存所能接收的报文段的数据字段的最大长度是 MSS 个字节” 。其他选项:窗口扩大选项、时间戳选项、选择确认选项。MSS (Maximum Segment Size) 是 TCP 报文段中的数据字段的最大长度。数据字段加上 TCP 首部才等于整个的 TCP 报文段。所以,MSS 是“TCP 报文段长度减去 TCP 首部长度”。
填充:这是为了使整个首部长度是 4 字节的整数倍。
TCP可靠传输的工作原理
IP 网络所提供的是不可靠的传输。如何实现可靠传输?主要有 ARQ协议(停止等待 ARQ 协议、连续 ARQ 协议)、滑动窗口协议。
注意关系:ARQ 协议是自动重传请求(Automatic Repeat-reQuest)。包含停止等待 ARQ (信道利用率低) 和连续 ARQ(信道利用率高),ARQ 协议实现连续发送是基于滑动窗口协议的。除此之外滑动窗口还可以用于流量控制。
自动重传请求(Automatic Repeat-reQuest,ARQ)是 OSI 模型中数据链路层和传输层的错误纠正协议之一。它通过使用确认和超时这两个机制,在不可靠服务的基础上实现可靠的信息传输。如果发送方在发送后一段时间之内没有收到确认帧,它通常会重新发送。ARQ 包括停止等待 ARQ 协议和连续 ARQ 协议。
ARQ协议
ARQ 协议的核心都是自动重传。
停止等待 ARQ 协议
停止等待 ARQ 协议要点:
停止等待。发送方每次只发送一个分组。在收到确认后再发送下一个分组。
编号。对发送的每个分组和确认都进行编号。
自动重传请求。发送方为每个发送的分组设置一个超时计时器。若超时计时器超时,发送方会自动重传分组。
简单,但信道利用率太低。
停止等待就是每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。
① 无差错情况
发送方发送分组,接收方在规定时间内收到,并且回复确认。发送方再次发送。
② 出现差错
在接收方 B 会出现两种情况:
B 接收 M1 时检测出了差错,就丢弃 M1,其他什么也不做(不通知 A 收到有差错的分组)。
M1 在传输过程中丢失了,这时 B 当然什么都不知道,也什么都不做。
在这两种情况下,B 都不会发送任何信息。
但 A 都必须重发分组,直到 B 正确接收为止,这样才能实现可靠通信。
问题1:A如何知道 B 是否正确收到了 M1 呢?
解决方法:超时重传
A 为每一个已发送的分组都设置了一个超时计时器。
A 只要在超时计时器到期之前收到了相应的确认,就撤销该超时计时器,继续发送下一个分组 M2 。
若 A 在超时计时器规定时间内没有收到 B 的确认,就认为分组错误或丢失,就重发该分组。
问题2:若分组正确到达B,但B回送的确认丢失或延迟了,A未收到B的确认,会超时重发。B 可能会收到重复的 M1 。B如何知道收到了重复的分组,需要丢弃呢?
解决方法:编号
A 为每一个发送的分组都进行编号。若 B 收到了编号相同的分组,则认为收到了重复分组,丢弃重复的分组,并回送确认。
B 为发送的确认也进行编号,指示该确认是对哪一个分组的确认。
A 根据确认及其编号,可以确定它是对哪一个分组的确认,避免重发发送。若为重复的确认,则将其丢弃。
③ 确认丢失
(1)若 B 所发送的对 M1 的确认信息丢失了,那么 A 在设定的超时重传时间内不能收到确认,但 A 并无法知道:是自己发送的分组出错、丢失了,或者 是 B 发送的确认丢失了。因此 A 在超时计时器到期后就要重传 M1。
(2)假定 B 又收到了重传的分组 M1。这时 B 应采取两个行动:
第一,丢弃这个重复的分组 M1,不向上层交付。
第二,向 A 发送确认。不能认为已经发送过确认就不再发送,因为 A 之所以重传 M1 就表示 A 没有收到对 M1 的确认。
④ 确认迟到
(1)传输过程中没有出现差错,但 B 对分组 M1 的确认迟到了(如网络阻塞等原因)。
(2)A 会收到重复的确认。对重复的确认的处理很简单:收下后就丢弃。
(3)B 仍然会收到重复的 M1,并且同样要丢弃重复的 M1,并重传确认分组。
注意:
在发送完一个分组后,必须暂时保留已发送的分组的副本,以备重发。
分组和确认分组都必须进行编号。超时计时器的重传时间应当比数据在分组传输的平均往返时间更长一些。
超时计时器的重传时间应当比数据在分组传输的平均往返时间更长一些。
⑤ 信道利用率
可以看出,当往返时间 RTT 远大于分组发送时间 TD 时,信道的利用率就会非常低。若出现重传,则对传送有用的数据信息来说,信道的利用率就还要降低。
自动请求重传
通常 A 最终总是可以收到对所有发出的分组的确认。如果 A 不断重传分组但总是收不到确认,就说明通信线路太差,不能进行通信。
使用上述的确认和重传机制,我们就可以在不可靠的传输网络上实现可靠的通信。
像上述的这种可靠传输协议常称为自动重传请求 ARQ (Automatic Repeat reQuest)。意思是重传的请求是自动进行的,接收方不需要请求发送方重传某个出错的分组。
流水线传输
为了提高传输效率,发送方可以不使用低效率的停止等待协议,而是采用流水线传输。流水线传输就是发送方可连续发送多个分组,不必每发完一个分组就停顿下来等待对方的确认。这样可使信道上一直有数据不间断地传送。由于信道上一直有数据不间断地传送,这种传输方式可获得很高的信道利用率。
这就演变出来连续 ARQ 协议。
连续ARQ协议
要点:自动请求重传 + 流水线。
基本思想
发送方一次可以发出多个分组。
使用滑动窗口协议控制发送方和接收方所能发送和接收的分组的数量和编号。
每收到一个确认,发送方就把发送窗口向前滑动。
接收方一般采用累积确认的方式。不必对分组逐个确认,而可以对按序到达的最后一个分组进行确认表示到这个分组为止的所有分组都已正确收到了。
采用回退 N(Go-Back-N)方法进行重传。如果发送方发送了前 5 个分组,而中间的第 3 个分组丢失了。这时接收方只能对前两个分组发出确认。发送方无法知道后面三个分组的下落,而只好把后面的三个分组都再重传一次。这就叫做 Go-back-N(回退 N),表示需要再退回来重传已发送过的 N 个分组。
连续 ARQ 协议是需要配合滑动窗口协议的。下面看看怎么搞。
TCP可靠传输的实现
上一节讲的是实现可靠传输的基本原理,这一节具体讲 TCP 是如何实现可靠传输的。分为三个部分。
滑动窗口协议
滑动窗口协议在在发送方和接收方之间各自维持一个滑动窗口,发送发是发送窗口,接收方是接收窗口,而且这个窗口是随着时间变化可以向前滑动的。它允许发送方发送多个分组而不需等待确认,提高了信道的利用率。TCP的滑动窗口是以字节为单位的。
① 基本流程
窗口是缓存的一部分,用来暂时存放字节流。发送方和接收方各有一个窗口,接收方通过 TCP 报文段中的窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其它信息设置自己的窗口大小。
发送窗口内的字节都允许被发送,接收窗口内的字节都允许被接收。如果发送窗口左部的字节已经发送并且收到了确认,那么就将发送窗口向右滑动一定距离,直到左部第一个字节不是已发送并且已确认的状态;接收窗口的滑动类似,接收窗口左部字节已经发送确认并交付主机,就向右滑动接收窗口。
TCP 使用流水线传输和滑动窗口协议实现高效、可靠的传输。
TCP 的滑动窗口是以字节为单位的。
发送方 A 和接收方 B 分别维持一个发送窗口和一个接收窗口。
发送窗口表示:在没有收到确认的情况下,可以连续把窗口内的数据全部发送出去。
接收窗口表示:只允许接收落入窗口内的数据。
发送窗口里面的序号 31 - 50 表示是允许发送的序号。发送窗口后沿的后面部分表示已经收到并且确认,这部分数据不需要继续保存。描述一个发送窗口需要维护三个指针,如下图所示。下图中如果 B 收到了 32、33 序号的数据,但是并没有收到 31 的数据,说明数据没有按序到达,所以 B 发送的确认报文段中的确认号仍然是 31(期望收到的序号)。
下图所示为 B 收到 31-33 的数据并交付主机,同时给 A 确认,其中窗口值为 20 ,确认值变为 34(即下一个期望收到序号为 34 的数据)。同时下图还收到了 37、38、40 序号的数据,但是未按序到达,所以只是暂存到接收窗口。此时 B 的接收窗口向前滑动到下一个期待接收的位置 34。
此时 A 收到确认号,发送窗口向前滑动。
如果 A 的发送窗口内的序号都已用完,但还没有再收到确认,必须停止发送。 如下图。
而如果 A 收到确认落在发送窗口内,那就可以使发送窗口继续向前滑动。
注意:
第一,A 的发送窗口并不总是和 B 的接收窗口一样大(因为有一定的时间滞后)。
第二,TCP 标准没有规定对不按序到达的数据应如何处理。通常是先临时存放在接收窗口中,等到字节流中所缺少的字节收到后,再按序交付上层的应用进程。
第三,TCP 要求接收方必须有累积确认的功能,这样可以减小传输开销。
其实真正的发送窗口值的大小还取决于网络的拥塞情况,发送窗口的上限值 = Min (接收方窗口值,拥塞窗口值)。
② 滑动窗口与缓存
发送缓存用来暂时存放:
发送应用程序传送给发送方 TCP 准备发送的数据;
TCP 已发送出但尚未收到确认的数据。
接收缓存用来暂时存放:
按序到达的、但尚未被接收应用程序读取的数据;
不按序到达的数据。
超时重传时间
重传机制是 TCP 中最重要和最复杂的问题之一。TCP 每发送一个报文段,就对这个报文段设置一次计时器。只要计时器设置的重传时间到但还没有收到确认,就要重传这一报文段。重传时间的选择是 TCP 最复杂的问题之一。
如果把超时重传时间设置得太短,就会引起很多报文段的不必要的重传,使网络负荷增大。但若把超时重传时间设置得过长,则又使网络的空闲时间增大,降低了传输效率。
如何设置超时重传时间?
TCP 采用了一种自适应算法,它记录一个报文段发出的时间,以及收到相应的确认的时间。这两个时间之差就是报文段的往返时间 RTT。计算加权平均往返时间 RTTs。超时重传时间 RTO (Retransmission Time-Out) 应略大于上面得出的加权平均往返时间 RTTs。
如何准确计算 RTTs?
存在的问题:TCP 报文段 1 没有收到确认。重传(即报文段 2)后,收到了确认报文段 ACK。
如何判定此确认报文段是对原来的报文段 1 的确认,还是对重传的报文段 2 的确认?
在计算平均往返时间 RTT 时,只要报文段重传了,就不采用其往返时间样本。这样得出的加权平均 RTTs 和 RTO 就比较准确。
选择确认SACK
问题:若收到的报文段无差错,只是未按序号,中间还缺少一些序号的数据,那么能否设法只传送缺少的数据而不重传已经正确到达接收方的数据?
答案是可以的。选择确认 SACK (Selective ACK) 就是一种可行的处理方法。其实大多数的实现还是重传所有未被确认的数据块。
TCP流量控制
概述
流量控制就是控制发送方发送速率,保证接收方来得及接收。
接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小(利用滑动窗口实现流量控制),从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据。
可能发生死锁
B 向 A 发送了零窗口的报文段后不久,B 的接收缓存又有了一些存储空间。于是 B 向 A 发送了 rwnd = 400 的报文段。
但这个报文段在传送过程中丢失了。A 一直等待收到 B 发送的非零窗口的通知,而 B 也一直等待 A 发送的数据。
如果没有其他措施,这种互相等待的死锁局面将一直延续下去。
为了解决这个问题,TCP 为每一个连接设有一个持续计时器 (persistence timer)。
持续计数器
只要 TCP 连接的一方收到对方的零窗口通知,就启动该持续计时器。
若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅携带 1 字节的数据),而对方就在确认这个探测报文段时给出了现在的窗口值。
若窗口仍然是零,则收到这个报文段的一方就重新设置持续计时器。
若窗口不是零,则死锁的僵局就可以打破了。
TCP拥塞控制
概述
在某段时间,若对网络中某资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种现象称为拥塞 (congestion)。
最坏结果:系统崩溃。
问题:增加资源能解决拥塞吗?
不能。这是因为网络拥塞是一个非常复杂的问题。简单地采用上述做法,在许多情况下,不但不能解决拥塞问题,而且还可能使网络的性能更坏。
网络拥塞往往是由许多因素引起的。
流量控制与拥塞控制的对比
流量控制 |
拥塞控制 |
---|---|
抑制发送端发送数据的速率,以使接收端来得及接收 |
防止过多的数据注入到网络中,使网络中的路由器或链路不致过载 |
是点对点通信量的控制,是端到端的问题 |
是一个全局性的过程,涉及到与降低网络传输性能有关的所有因素 |
使用滑动窗口实现 |
使用拥塞窗口变量+拥塞控制算法实现,还要配合滑动窗口 |
滑动窗口与拥塞窗口的区别
滑动窗口是接收窗口,就是 TCP 头的那个窗口,可以理解为一块内存,一方面他要接收数据,一方面他要向应用层交付数据。
而拥塞窗口是一个变量。
拥塞控制所起的作用
解决拥塞问题的两条思路:
增加网络可用资源;
减少用户对资源的需求。
TCP的拥塞控制方法
拥塞控制:基于拥塞窗口变量+几种拥塞控制算法实现。
TCP 采用基于拥塞窗口的方法进行拥塞控制。该方法属于闭环控制方法。
TCP发送方维持一个**拥塞窗口 cwnd** (Congestion Window) 的变量。发送端利用拥塞窗口根据网络的拥塞情况调整发送的数据量。
发送窗口大小不仅取决于接收方窗口,还取决于网络的拥塞状况,所以真正的发送窗口值为:
发送窗口的上限值 = Min (接收方窗口值,拥塞窗口值) = Min(rwnd, cwnd)
当 rwnd < cwnd 时,是接收方的接收能力限制发送窗口的最大值。
当 cwnd < rwnd 时,则是网络的拥塞限制发送窗口的最大值。
发送方让自己的发送窗口取为拥塞窗口和接收方的接受窗口中较小的一个。
控制拥塞窗口的原则
只要网络没有出现拥塞,拥塞窗口就可以再增大一些,以便把更多的分组发送出去,这样就可以提高网络的利用率。
但只要网络出现拥塞或有可能出现拥塞,就必须把拥塞窗口减小一些,以减少注入到网络中的分组数,以便缓解网络出现的拥塞。
拥塞的判断
TCP拥塞控制算法
四种拥塞控制算法( RFC 5681) :
慢开始 (slow-start)
拥塞避免 (congestion avoidance)
快重传 (fast retransmit)
快恢复 (fast recovery)
TCP 拥塞控制流程图。
① 慢开始算法
目的:用来确定网络的负载能力或拥塞程度。
算法的思路:由小到大逐渐增大拥塞窗口数值。
两个变量:
(1)拥塞窗口:初始拥塞窗口值。2 - 4 个最大报文段,窗口值逐渐增大。
(2)慢开始门限(ssthresh):防止拥塞窗口增长过大引起网络拥塞。
拥塞窗口 cwnd 控制方法:在每收到一个对新的报文段的确认后,可以把拥塞窗口增加最多一个 SMSS 的数值。
每经过一个传输轮次,拥塞窗口就加倍,即**cwnd = cwnd * 2。一个传输轮次所经历的时间其实就是往返时间 RTT**。
“传输轮次”更加强调:把拥塞窗口 cwnd 所允许发送的报文段都连续发送出去,并收到了对已发送的最后一个字节的确认。
例如,拥塞窗口 cwnd = 4,这时的往返时间 RTT 就是发送方连续发送 4 个报文段,并收到这 4 个报文段的确认,总共经历的时间。
设置慢开始门限状态变量 ssthresh。
慢开始门限 ssthresh 的用法如下:
当 cwnd < ssthresh 时,使用慢开始算法。
当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。
当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞避免算法。
② 拥塞避免算法
当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。
思路:让拥塞窗口 cwnd 缓慢地增大,避免出现拥塞。
超时之前,每经过一个传输轮次,拥塞窗口 cwnd = cwnd + 1。
使拥塞窗口 cwnd 按线性规律缓慢增长。
在拥塞避免阶段,具有 “加法增大” (Additive Increase) 的特点。
当网络出现拥塞时:
无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(重传定时器超时):
(1)ssthresh = max (cwnd / 2,2):降低门限值(取一半)。
(2)cwnd = 1: 拥塞窗口变为 1。
(3)执行慢开始算法:重新执行慢开始。
目的:迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。
慢开始与拥塞避免算法的举例:
“拥塞避免”并非指完全能够避免了拥塞。利用以上的措施要完全避免网络拥塞还是不可能的。
“拥塞避免”是说在拥塞避免阶段把拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞。
③ 快重传算法
发送方只要一连收到三个重复确认,就知道接收方确实没有收到报文段,因而应当立即进行重传(即“快重传”),这样就不会出现超时,发送方也不就会误认为出现了网络拥塞。
使用快重传可以使整个网络的吞吐量提高约 20%。
不难看出,快重传并非取消重传计时器,而是在某些情况下可以更早地(更快地)重传丢失的报文段。
采用快重传 FR (Fast Retransmission) 算法可以让发送方尽早知道发生了个别报文段的丢失。
快重传算法首先要求接收方不要等待自己发送数据时才进行捎带确认,而是要立即发送确认,即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认。
下图中仅仅是丢失了 M3,其实并没有发生拥塞。此时连续收到其他三个重复确认,就说明其实网络大概率没有拥塞,而仅仅是发生了 M3 的丢失。此时启用快重传立即重传 M3。
④ 快恢复算法
根据上图所示。当发送端收到连续三个重复的确认时,由于发送方现在认为网络很可能没有发生拥塞,因此现在不需要执行慢开始算法,而是执行快恢复算法 FR (Fast Recovery) 算法:
(1)慢开始门限 ssthresh = 当前拥塞窗口 cwnd / 2 ;
(2)新拥塞窗口 cwnd = 慢开始门限 ssthresh ;
(3)开始执行拥塞避免算法,使拥塞窗口缓慢地线性增大。
AIMD
拥塞避免算法中,拥塞窗口是按照线性规律增大的。这常称为“加法增大” AI (Additive Increase)。
当出现超时或 3 个重复的确认时,就要把门限值设置为当前拥塞窗口值的一半,并大大减小拥塞窗口的数值这常称为“乘法减小”MD (Multiplicative Decrease)。
二者合在一起就是所谓的 AIMD 算法。
TCP建立连接
TCP 是面向连接的协议。
TCP 传输数据有三个阶段:
连接建立
数据传送
连接释放
TCP 连接的管理就是使 TCP 连接的建立和释放都能正常地进行。
TCP 连接建立过程中要解决的三个问题:
要使每一方能够确知对方的存在。
要允许双方协商一些参数(如最大窗口值、是否使用窗口扩大选项和时间戳选项以及服务质量等)。
能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配。
连接过程
TCP 建立连接的过程叫做握手。
握手需要在客户和服务器之间交换三个 TCP 报文段。称之为三报文握手。
SYN 是同步号,seq 是数据的第一个字节序号,连接请求也有数据,只不过数据字节数为 1。
服务器收到连接请求,SYN 也为 1。并使 ACK = 1,表示收到客户端的连接请求。只有当 ACK = 1 时确认号 ack 字段才有效。所以必须设置 ACK = 1。由于服务器收到客户端发送的序号 seq = x,说明服务器收到这一个字节的数据,因此期待客户端下一个发送的数据的第一个字节是 seq = x + 1。所以确认号 ack = x + 1。同时服务器也选择一个自己的序号 seq = y。
这里要注意区分 ACK(标志位,为 1 时 ack 才有效, ACK 表示回复对方已经收到对方的消息) 与 ack(确认号,用于确认已经收到数据,并且回复下一个期待收到的数据)。
客户端收到服务器的第二次握手,需要对服务器进行第三次握手,此时 ACK = 1,表示收到服务端的第二次握手信息。由于之前客户端发送的是序列号 seq = x。而且服务端也发回来的确认号也是 x + 1。因此如果是正常的握手报文则客户端第三次握手的数据报文就是 seq = x + 1。同时客户端也收到服务器的 seq = y,需要确认收到了这个,因此回复给服务器的确认中确认号变为 ack = y + 1。
此时完成三次握手。之后进行数据传输。
三次握手整体过程总结
简化一点(面试用):相当于客户端和服务端都给对方发送了 SYN 和 ACK 信号。
三次握手的原因
为什么要进行第三次?只握手两次不行?
原因 1:
三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的。
采用三报文握手主要是为了防止已失效的连接请求报文段突然又传送到了,因而产生错误。
第一次握手:Client 什么都不能确认;Server 确认了对方发送正常,自己接收正常。
第二次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:对方发送正常,自己接收正常。
第三次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送、接收正常。
三次握手是为了确定客户端与服务端都能正常收发。
原因 2:
进行第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接,占用服务器资源。
客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的连接确认。客户端等待一个超时重传时间之后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。如果有第三次握手,客户端会忽略服务器之后发送的对滞留连接请求的连接确认(因为序号这些对应不上),不进行第三次握手,因此就不会再次打开连接。
为什么要传回 SYN
接收端传回发送端所发送的 SYN 是为了告诉发送端,我接收到的信息确实就是你所发送的信号了。
SYN 是 TCP/IP 建立连接时使用的握手信号。在客户机和服务器之间建立正常的 TCP 网络连接时,客户机首先发出一个 SYN 消息,服务器使用 SYN-ACK 应答表示接收到了这个消息,最后客户机**再以 ACK **消息响应(Acknowledgement[汉译:确认字符 ,在数据通信传输中,接收站发给发送站的一种传输控制字符。它表示确认发来的数据已经接受无误。])。这样在客户机和服务器之间才能建立起可靠的TCP连接,数据才可以在客户机和服务器之间传递。
TCP释放连接
TCP 连接释放过程比较复杂。
数据传输结束后,通信的双方都可释放连接。
TCP 连接释放过程是四报文握手。
释放过程
举个例子:A 和 B 打电话,通话即将结束后,A 说“我没啥要说的了”,B回答“我知道了”,但是 B 可能还会有要说的话,A 不能要求 B 跟着自己的节奏结束通话,于是 B 可能又巴拉巴拉说了一通,最后 B 说“我说完了”,A 回答“知道了”,这样通话才算结束。
双方均可释放连接,而 TCP 连接是只有客户端才能发起连接。
假设客户端主动释放连接。
客户端发送 FIN = 1。并且其数据部分序号为 seq = u(仅一个字节数据)。
服务器收到释放连接的请求,那么直接回复 ACK = 1,表示确认收到客户端的释放请求。同时回复其确认号 ack = u + 1(即服务端期望客户端发送的下一个字节)。
同时:如果服务端还有未发送完成的数据,此时服务端可以继续发送给客户端,直到数据发送完成(注意此时只能服务端给客户端发送数据,也就是主动发起释放连接的一方只能接受不能再发送了)。
之后服务器发送另一个释放消息。即 FIN = 1,同时 ACK = 1,表示收到客户端的消息,此时 ack 有效,且 ack = u + 1 。同时发送自己的序列号 seq = w。
客户端收到服务器的释放报文后,需要再次确认。
此时 ACK = 1(确认信息有效),同时 seq = u + 1(客户端前一次发送 u 的基础上加 1),ack = w + 1(表明收到服务器的 seq = w 的信息)。四次挥手完成。
同时客户端进入 Time-Wait 状态,等待 2MSL 的时间。
连接释放整体流程:
简化一点(面试用):相当于客户端和服务端都给对方发送了 FIN 和 ACK 信息,只不过服务端的 分成了两次,所以变成了四次挥手。
四次挥手的原因
客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。
TIME_WAIT
客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL。这么做有两个理由:
确保最后一个确认报文能够到达。如果 B 没收到 A 发送来的确认报文,那么就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。
等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。
其他
① 保活计时器
用来防止在 TCP 连接出现长时期的空闲,比如客户端直接断电,来不及发送释放的报文。
保活计时器 通常设置为 2 小时 。若服务器过了 2 小时还没有收到客户的信息,它就发送探测报文段。若发送了 10 个探测报文段(每一个相隔 75 秒)还没有响应,就假定客户出了故障,因而就终止该连接。
② TCP有限状态机
箭头旁边的字,表明引起这种变迁的原因,或表明发生状态变迁后又出现什么动作。
图中有三种不同的箭头。
(1)粗实线箭头表示对客户进程的正常变迁。
(2)粗虚线箭头表示对服务器进程的正常变迁。
(3)细线箭头表示异常变迁。
TCP连接状态
CLOSED:初始状态。
LISTEN:服务器处于监听状态。
SYN_SEND:客户端socket执行CONNECT连接,发送SYN包,进入此状态。
SYN_RECV:服务端收到SYN包并发送服务端SYN包,进入此状态。
ESTABLISH:表示连接建立。客户端发送了最后一个ACK包后进入此状态,服务端接收到ACK包后进入此状态。
FIN_WAIT_1:终止连接的一方(通常是客户机)发送了FIN报文后进入。等待对方FIN。
CLOSE_WAIT:(假设服务器)接收到客户机FIN包之后等待关闭的阶段。在接收到对方的FIN包之后,自然是需要立即回复ACK包的,表示已经知道断开请求。但是本方是否立即断开连接(发送FIN包)取决于是否还有数据需要发送给客户端,若有,则在发送FIN包之前均为此状态。
FIN_WAIT_2:此时是半连接状态,即有一方要求关闭连接,等待另一方关闭。客户端接收到服务器的ACK包,但并没有立即接收到服务端的FIN包,进入FIN_WAIT_2状态。
LAST_ACK:服务端发动最后的FIN包,等待最后的客户端ACK响应,进入此状态。
TIME_WAIT:客户端收到服务端的FIN包,并立即发出ACK包做最后的确认,在此之后的2MSL时间称为TIME_WAIT状态。
TCP 协议保证可靠传输总结
上面说了这么多,TCP 协议是如何保证传输可靠的??
应用数据被分割成 TCP 认为最适合发送的数据块。
TCP 给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用层。
校验和: TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
TCP 的接收端会丢弃重复的数据。
流量控制: TCP 连接的每一方都有固定大小的缓冲空间,TCP的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议。 (TCP 利用滑动窗口实现流量控制)
拥塞控制: 当网络拥塞时,减少数据的发送。
ARQ 协议: 也是为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认。在收到确认后再发下一个分组。
超时重传: 当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。