计网运输层

运输层

TCP与UDP区别

  • 用户数据报协议 UDP(User Datagram Protocol)是无连接的,尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加 UDP 首部),支持一对一、一对多、多对一和多对多的交互通信。

  • 传输控制协议 TCP(Transmission Control Protocol)是面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块),每一条 TCP 连接只能是点对点的(一对一)

UDP首部

在这里插入图片描述
首部字段只有 8 个字节,包括源端口、目的端口、长度、检验和。12 字节的伪首部是为了计算检验和临时添加的。

一:初识TCP

差错校验和自动重复请求( ARQ)是通信的基础

1:ARQ与重传

ARQ:自动重复请求。对于发生差错的请求,一直尝试重新发送请求,直到被正确处理。

为了保证接收方一定能收到分组,发送方会有重传机制,引起重传的事件很多:

  • 分组丢失,接收方没有收到,自然没有ACK了
  • 接收方虽然收到了分组,但是ACK丢失。
  • 由于网络延迟,分组或者ACK迟迟在网络中阻塞。
  • 接收方收到的分组有错误。接收方通过校验和检测到有差错时,不会返回ACK
    这四种情况对于发送方来说看到的都是一样的,都不会返回ACK

还有一个重要的问题就是什么时间内没有收到ACK就进行重传,也就是何确定超时时间,后面会讲到。(通常超时计时器也不是为每个分组设置,而是发送一个窗口的分组设置一个重传计时器。)

每个分组要携带序号,接收方通过序号判断自己有没有接收到这个分组,如果已经收到过,则丢弃。(但是必须返回ACK)发送方收到ACK后又继续发送下一个分组。但是这样做效率太低,每次发送方发送一个分组以后,就进入“等待”的状态,直到收到ACK再发送新的分组,或者超时后进行重传。效率太低。

于是就尝试一次可以传输多个分组,由接收方对收到的分组进行顺序重组,因为由于网络延迟与路由等原因,分组不一定按照顺序到达接收方。而此时,还要采用累计确认的机制来告诉接收方自己收到了哪些分组,而不是为每一个分组都返回一个确认ACK。以提升效率。这只是基础易懂的点

除此之外还有一些问题需要考虑,比如一次最多只能发送多少分组进入网络,才不会导致网络的阻塞和接收方来得及接收呢?等等的一些问题,就需要使用到窗口机制来解决了。

2:累计确认

累积确认这个概念应该不只适用于TCP协议,也适用其他层,比如链路层。

具体到TCP,它对字节编号。比如发送方发了包1,包2,包3;包1含字节0到10,包2含字节11到20,包3含字节21到30。接受方成功收到包1,包2。那么接受方发回一个包含确认序号21的包,发送方就知道字节0到20(包1,包2)都成功收到,要重发的只需从字节21开始。

ACK并不会立即返回,而是会稍等片刻。(以达到累计确认的目的,如果立即发送,那就和为每一个报文发送一个ACK没有区别了)

3:分组窗口与滑动窗口

发送方和接收方可以维护一个窗口。

这样发送方一次最多就可以发送一个窗口数量的分组。暂且先不考虑窗口大小确定为多少。

发送方窗口中的分组是已经发送但是还没有收到ACK的分组。窗口左边是已经确认的分组,右边是还没有轮到发送的分组,因为还没有进入窗口。进入窗口的分组会被立即发送。(所以下图还是有点不对)。
左边的副本可以被释放,正在发送窗口中的分组还必须保存副本以备重传

什么又是滑动窗口?
比如现在窗口中有3,4,5三个分组,都未收到ACK,窗口大小也为3.如果此时,收到了分组3的ACK,那么窗口便可以向右滑动一个位置,这样分组三从左边离开窗口,分组三的副本便可以释放了。分组6进入窗口,这时候窗口内的分组为4,5,6.分组6未发送,但是这时候进入了窗口就得到了发送机会,发送方发送分组6.这便是滑动窗口协议

接收方窗口中的分组是期望被接收的分组。(会分配内存来保存他们)不期望接收的分组即使到达但是因为内存的限制也会被丢弃。未按序到达的分组只要在窗口内就会被保存。

在这里插入图片描述

关于窗口应该设置为多大,或者接收方来不及接收发送方发过来的数据一个怎么办?增大或者减小发送方窗口?接下来看看窗口是如何实现流量控制和拥塞控制的。

4:变量窗口:流量控制和拥塞控制

什么是流量控制?
流量控制是指接收方相对于发送方太慢的情况,也就是发送方速率大于接收方速率

流量控制的两种方式:
一:基于速率的控制:给发送方指定一个速率,发送方永远不能超过这个发送速率。适合流应用程序,例如广播和组播发现。
二:基于窗口的流量控制,是使用滑动窗口的流行方法。发送方窗口大小不固定,而是可以随着时间变化。这就需要接受方可以通知发送方应该调整窗口为多大。这一般称为窗口通告或者窗口更新。窗口通告和ACK是一个分组携带的。这样接受方就可以根据自己的接收能力来返回给发送方一个窗口通告来使发送方调整窗口大小。

但是这样还会有问题,因为发送方和接受方还有中间网络,中间路由器可能无法承受现在的流量,就会出现丢包。这就需要拥塞控制,是进行流量控制的特殊机制,主要是针对于中间网络。拥塞控制会在中间网络拥堵时减小发送方的速率,后面会专门讨论。

5:设置超时重传

要等多久才能重传?这是一个非常复杂的问题。

直观上看,应该是 发送分组的时间+接受方处理它和发送一个ACK的时间+ACK返回到发送方的时间+发送方处理ACK的时间

但是准确确定这个时间是不现实的,只能估计,这称为往返时间估计。选择一组RTT的均值是最可能的。

但是RTT的均值能够作为重传超时时间吗?显然是不能的

因为均值并不是极值,许多RTT都会比这个平均时间大就会导致很多不必要的重传,很明显,超时时间应该设置为比均值要大的某个值,但是又不能太大,否则会导致网络空闲降低吞吐量。具体如何确定超时时间后面会讨论。

6:TCP引入

简单介绍了可靠传输模型,简单了解下一TCP模型

TCP提供了一种面相连接,可靠的字节流服务。

TCP发送的字节流由IP数据报携带,形成一个个的分组。每个分组包含一个序列号,这个序列号是该分组头一个字节在字节流中的偏移量。
允许分组在传送中是可变大小的,并且可以组合,称为重新组包。最好是每个TCP的报文段(TCP传送给IP的块)大小最大且不会被IP分片刚好放到网络层的数据报中。

TCP通常是为一个窗口的数据设置一个重传计时器
累计确认: 当接收端接收到一个分组时,并不会立即发送确认,而一般会延迟片刻。TCP使用的ACK是累积的,一个指示字节N的ACK暗示所有到N的字节都成功被接收了

TCP是全双工的,一个方向的数据流TCP报文段也可以包含相反方向上的报文段的一个ACK。和窗口通告等字段

使用序列号,接收端可以丢弃重复到达的分组,接收乱序到达但是在窗口范围内的分组

7:TCP头部和封装

TCP分组叫报文段
在这里插入图片描述

TCP头部不加选项20字节,选项最多40字节,所以TCP头部最长可达60字节

  • 源与目的端口号加上IP头部中的源和目的IP地址唯一的标识了一组TCP连接

  • 序列号 :报文段第一个字节的偏移,当到达2的32次方-1后再循环回到0;

  • 确认号 (简称ACK号或者ACK字段):期望收到的下一个报文段的序号。这个字段只有ACK位字段被启用的情况下才有效

  • 头部长度)数据偏移 :指的是数据部分距离报文段起始处的偏移量,实际上指的是首部的长度。这是一个必要的字段,因为头部长度可变。

  • 确认 ACK :当 ACK=1 时确认号字段有效,否则无效。TCP 规定除了最初建立连接时的 SYN 包之外该位必须设置为 1 。

  • 同步 SYN :客户端发送给服务端的第一个报文段的SYN字段被启用。这叫做SYN报文段。SYN报文段也要包含一个序列号,这是一个初始序列号ISN,不是0或者1 这上一种安全措施。这个方向上的数据的第一个字节的序列号是ISN+1,因为SYN报文段会消耗一个序列号。

这里有一个知识点,只有消耗了序列号的报文段才能通过重传进行可靠传输,因此SYN是能够被可靠传输的,但是不消耗序列号的ACK则不能进行可靠传输,就可能丢失

  • 终止 FIN :用来释放一个连接,当 FIN=1 时,表示此报文段的发送方的数据已发送完毕,并要求释放连接。

  • RST:重置连接,用于重置报文段中

  • 窗口大小:TCP的流量控制是由每个端点使用窗口大小字段来通告一个窗口大小来完成的。窗口大小是字节数,这是一个16位字段,限制了最大窗口字节数,从而限制了TCP的性能。后面我们可以看到窗口缩放选项可以允许对这个值进行缩放。

  • 校验和字段:用来判断报文段是否被修改。

二:TCP连接管理

TCP是一种面向连接的单播协议,发送数据之前通信双方必须建立一条连接

如前文所述,TCP的服务模型是一个字节流。TCP必须检测并且修补所有在IP层及以下层产生的数据传输问题。(比如丢包重复及错误)

一个TCP连接由一个四元组构成,它们分别是两个IP地址和两个端口号,一对套接字能唯一标识该连接

1:三次握手(连接)

在这里插入图片描述
通过三次握手,服务端与客户端建立连接,并且交换彼此初始序列号(ISN)

A为客户端,B为服务端

  • 首先 B 处于 LISTEN(监听)状态,等待客户的连接请求。
  • A(主动发起者) 向 B 发送一个SYN报文,SYN=1,ACK=0,指明它想要连接的端口。并且携带自己的初始序列号告知给服务端
  • B 收到连接请求报文,如果同意建立连接,则向 A 发送连接确认SYN报文,SYN=1,ACK=1,确认号为 x+1,同时也选择一个初始的序号 y,通过这个SYN报文段发送给客户端。

!!!:每发送一个SYN报文段,序列号就要加一。也就是说SYN报文段也消耗一个序号。这样可以保证即使没有包含数据的SYN的报文段也具备重传的功能。

  • A 收到 B 的连接确认报文后,为了确认服务端的SYN报文,还要向 B 发出确认,确认号为 y+1,序号为 x+1。
  • B 收到 A 的确认后,建立连接完成。

三次握手的目的不仅仅是让通信双方了解一个连接正在建立,还在在于通过利用数据包的选项来承载特殊信息(例如MSS),以及交换初始序列号

SYN报文段也是能够承载数据的,基本没被使用。了解

1.1:三次握手作用

  • 建立一个连接
  • 交换初始序列号
  • 利用数据包的选项来承载特殊信息(例如MSS)

1.2:三次握手原因

1:防止连接资源的浪费

第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。

客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的连接确认。客户端等待一个超时重传时间之后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。如果有第三次握手,客户端通过序列号判断这是一个历史SYN报文段,客户端会发送一个重置报文段,终止历史连接。

而如果是当前连接就可以正常进行第三次握手建立连接。

2:交换初始序列号
前文已讲清楚

3:避免历史连接的初始化
其实与第一个原因差不多。第三次发送重置报文段就可以终止历史连接。

2:四次挥手(关闭)

在这里插入图片描述
连接的任意一方都可以发起一个关闭操作,此外,虽然少见,但是支持通信双方同时关闭连接的操作。

以下描述不讨论序号和确认号,因为序号和确认号的规则比较简单。并且不讨论 ACK,因为 ACK 在连接建立之后都为 1。

  • A (连接的主动关闭者)发送连接释放FIN报文,FIN=1。以及接收方希望看到的序列号K和ACK
  • 连接的被动关闭者将序号K加一作为响应的ACK。表明成功收到发送方发送的连接关闭请求。通常,上层的应用程序会被告知另一端已经提出了关闭连接的请求
  • 此时 TCP 属于半关闭状态,B 能向 A 发送数据但是 A 不能向 B 发送数据。
  • 当 B 不再需要连接时,B变身为主动关闭者,发送连接释放FIN报文,FIN=1。以及序号。
  • A 收到后发出ACK确认对方的 FIN报文,进入 TIME-WAIT 状态,等待 2 MSL(最大报文存活时间)后释放连接。
  • B 收到 A 的确认后释放连接。

什么是MSL?
MSL 是 Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
扩充:RTT往返时间,TTL路由器最大跳数

四次握手的原因

因为双方关闭自己到对方这一流向的数据传输都需要发送一个FIN报文段。对方则需要一个ACK报文段进行确认,但是这里对方的确认报文一半却不能与对方的FIN报文段一起发送,因为对方可能还需要发送数据,暂时不关闭连接。

可知,服务端通(被动关闭者)常需要等待完成数据的发送和处理再断开连接,所以服务端的 ACK和 FIN 一般都会分开发送,从而比三次握手导致多了一次。

所以,在一般情况下,关闭一个连接需要四次握手。

半关闭

例如A是客户端,B是服务端。
在这里插入图片描述

假设A方发起半关闭请求(任何一方都可以发起)。那么A放无法再传输数据给B,但是B还可以发送数据给A,而且虽然半关闭了,但是A任然能够对B响应ACK。中间B可以发送任意多组数据给A。

直到最后B也发起关闭请求,那么连接才算完全关闭。

3:同时打开与关闭

同时打开

在这里插入图片描述
同时打开与三次握手不一样,是四次握手。

通信双方在接收到来自对方主机的SYN之前必须先发送一个SYN,两个SYN经过网络送达对方。

没有任何一端称为客户或服务器,因为每一端既是客户又是服务器。

只打开了一个连接而不是两个

同时关闭

在这里插入图片描述
同时发起关闭请求。在收到对方的FIN请求前先发送自己的FIN请求。

数量上来说还是四次握手

4:初始序列号

在一个连接中,只要由合适的IP地址,端口号和符合逻辑的序列号(也就是在窗口中)以及正确校验的报文段都会被接收方接收。

但是由于网络路由的原因可能会出现延迟到达的原因,而如何判断这个延迟到达的数据是否是本连接的一个报文段是一个问题,因为四元组相同,序列号可能也在窗口内。初始化序列号可以解决这个问题。

在发送用于建立连接的SYN之前,通信双方都会选择一个初始序列号。而且这个初始序列号会随着时间改变。因此每一个连接都有不同的初始序列号。目的是为了防止与其他的连接初始化序列号重合的问题。尤其是同一连接的不同实例初始序列号。(同一套接字标识的新老连接)

如果是固定序列号的话!就有可能出现旧连接的报文被新连接成功接收了。

所以一个TCP报文段只有同时具备连接的四元组和序列号在当前窗口内,才会在通信过程中被对方认为是正确的。

但是如果序列号不一样,即使是上一次关闭了的同一连接的报文段延迟到达,但是序号并不在新连接的接收范围内(窗口)就会丢弃。

5:连接建立超时

若干问题可能导致连接无法建立,最常见的是服务器关闭。

无法连接时(得不到服务器回应),客户端TCP为了建立连接会频繁的发送SYN报文段,在首个报文段发送出去后仅2秒就发送第二个报文段,第三个报文段则是这之后的4秒,第四个报文段则是在第三个报文段发送出去后的第八秒。以此类推,这一行为被称为指数回退

可以配置发送初始SYN的次数,一般默认为5次,尝试完之后都没有连接成功就是连接建立超时,建立连接失败。

6:TCP头部选项(选项最大40字节)

TCP头部最长60字节,20+40.

TCP选项的第一个字节是选项的种类,种类0是选项列表结束选项(EOL),种类1是用于填充(NOP)。这两个选项得到长度是1字节,其余选项的长度包括种类和自身的字节数。

需要注意的是TCP头部的长度应该是4字节的倍数

所以不足4字节倍数的时候使用NOP来进行填充。

6.1:最大段大小选项(MSS)

允许从对方接收到的最大报文段大小,因此这也是通信双方能使用的最大报文段。

MSS只记录TCP数据的字节数不包括其他相关的TCP头部和IP的头部当建立一条TCP连接时,通信的每一方都要在自己的SYN报文段的MSS选项中说明主机允许的最大段大小。

最大段大小默认为536字节。

因为任何主机都要至少能够处理576字节的IPV4数据报。如果按照最小的IPV4与TCP头部计算,TCP协议要求每次发送时的最大段大小为536字节,这样正好可以组成一个576(536+20+20)字节的数据报。

看了IP分片再看432页第二段。

6.2:选择确认选项(SACK)

由于TCP的报文段可能会乱序到达,就会出现空洞。

如果TCP发送方能够了解接收方当前的空洞(以及在接收序列中超出空洞的乱序数据块),它就能在报文段丢失或者被接收方遗失时更好的进行重传工作。TCP的选择确认SACK提供了上述功能。如果接收方能够提供选择确认信息,发送方能够合理的利用这些信息,那么上述方案将会变得非常有效。

通过接收SYN(或者SYN+ACK)报文段中的“允许选择确认”选项,TCP通信方会了解到自身具有了发布SACK的能力。当接收到乱序的数据时,它就能提供一个SACK选项来描述这些乱序的数据,从而帮助对方有效的重传。SACK信息保存于SACK选项中,包含了接收方已经成功接收的数据块的序列号范围。每一个范围被称为一个SACK块,由一对 32位的序列号表示。因此,一个SACK选项包含了N个SACK块,长度为8N+2个字节。增加的两个字节用于保存SACK选项的种类和长度。

由于TCP头部选项空间有限,一个报文段中最多有三个SACK块。

只有SYN报文才能包含“允许选择确认”选项,但是只要发送方发送了该选项,但是SACK选项能够通过任何报文段发送。

6.3:窗口缩放选项

能够有效的将窗口大小字段的范围从16位扩展到30位的大小。

原理是使用窗口缩放选项对这16位窗口大小字段有效的左移。这样事实上可以将窗口数值扩大到2s次方倍,S是比例因子,也就是窗口缩放选项。

窗口缩放选项的取值是0到14,包含14,代表着左移多少位。

该选项只能出现在连接双方连接时的SYN报文段中,因此当连接建立以后比例因子是与方向绑定的。

假设我们正在使用窗口缩放选项,发送出去的窗口移动数值为s,而接收到的窗口移动数值为R。这样,我们从对方接收到每一个16位的窗口通告都需要座椅R位才能获得真实窗口大小。每次向对方发送窗口通告时,都会将32位的窗口大小向右移动S位,然后再填入到头部的窗口通告中

只能在SYN报文段中设置的选项:

  • MSS选项,最大段选项
  • 窗口缩放选项
  • 允许选择确认选项

前两个必须设置?第三个支持这个功能才会设置该选项

6.4:时间戳选项与防回绕序列号

  • 计算RTT与重传超时
  • 防回绕序列号(什么是序列号回绕?)

时间戳包括两部分:戳数值字段(TSV) 和 时间戳回显重试字段(TSER)

时间戳选项要求发送方在每一个报文段中添加2个4字节的时间戳数值。接收方将会在确认中反映这些数值,允许发送方针对每一个接收到的ACK估算TCP连接的往返时间。

因为TCP使用的是累计确认,所以必须指出是“每个接收到的ACK”而不是“每个报文段"。其他报文段不是对发送方发送报文的确认,是无法拿来计算往返时间的

发送方将发送报文时主机的时间戳(a1)设置到TSV中作为时间戳的第一个部分,接收方接收到报文段后将a1复制到返回ACK的TSER上作为时间戳的第二部分,然后再设置自己当前返回ACK的时间戳到返回ACK的TSV上作为时间戳的第一部分,返回ACK。收到ACK的发送方通过自己主机当前时间戳a2,就可以计算出RTT是a2-a1.

所以时间戳的作用之一就是计算RTT(往返时间)以计算重传超时,通过时间戳选项我们就可以更加精确的估算往返时间RTT。

双方并不需要进行时钟同步,也不需要关心时间戳的单位,推荐发送者每秒钟至少将时间戳加一。

也提供了防止接受旧报文段与判断报文段正确的方法。这被称为防回绕序列号。

首先要明白序列号在达到最大数后会回绕(从0开始)。如果之前旧连接一个报文在网络中阻塞,一段时间后才到达服务器,而且该阻塞报文的生存时间小于MSL。并且到达时,因为序列号回绕了。此阻塞报文段的序列号恰好在当前窗口内,按以前的规则就被正确接收了,但是有了时间戳选项,通过检查到该阻塞报文段的时间戳小于最近有效时间戳,就会包该报文段丢弃。

最近有效时间戳:就是最近收到的报文段的时间戳。

所以通过时间戳很好的防止了回绕序列号!

回绕序列号情况的发生要满足的条件:

  • 序列号回绕
  • 报文段阻塞
  • 该报文段是回绕前的序列号,但是由于阻塞与会绕后的序列号相同
  • 该报文段生存时间没有超过MSL,否则已经被网络丢弃,就不用被防回绕序列号算法处理了。

例子看书上435页。

6.5:用户超时选项

用户超时选项(UTO)是一个相对较新的TCP的功能。

用户超时数值(USER—TIMEOUT)指明了TCP发送者在确认对方未能成功接收数据之前愿意等待该数据ACK确认的时间。

用户超时选项允许TCP通信方将自己的用户超时数值告知连接另一方。这样方便了接受方调整自己的行为

用户超时选项的数值是建议性的,另一方只是作为参考,并不会一定遵循。

6.6:认证选项

用于增强连接的安全性。

密钥。加密等功能。

7:TCP的路径最大传输单元的发现(需深入)

MTU是指两台主机之间的路径的所有网络报文段中最大传输单元的最小值。

知道路径最大传输单元能够有助于一些协议避免分片。比如TCP。

MTU与MSS的区别
MTU是链路层协议承载上层协议数据的有效载荷部分的大小,比如能承载多大的IP数据报
MSS则是最大段大小,是TCP报文段除去头部及选项的区域

如何发现路径MTU待整理

三:TCP状态转换

1:连接与关闭状态转换图

在这里插入图片描述

1.1:三次握手的状态转换

  • 初始化时,TCP从CLOSED状态启动
  • 首先根据是主动打开方或者被动打开方,TCP将分别快速转换到SYN_SENT状态LISTEN状态
  • 主动打开方发送SYN报文段后进入SYN_SENT状态
  • 被动打开方接收到SYN,并且发送SYN+ACK后进入SYN_RCVD状态
  • 主动打开方接收到SYN+ACK然后发送ACK后进入ESTABLISHED状态
  • 被动打开方接收到ACK后进入ESTABLISHED状态

1.2:四次挥手的状态转换

  • 最初都在ESTABLISHED状态
  • 主动关闭方发送FIN后进入FIN_WAIT1状态。
  • 被动关闭方接收到SYN并且返回ACK后进入CLOSE_WAIT状态
  • 主动关闭方接收到ACK后进入到FIN_WAIT2状态
  • 下面被动关闭方开始关闭
  • 被动关闭方发送SYN后进入LAST_ACK状态
  • 主动关闭方接收到SYN后并且发送ACK进入TIME_WAIT状态
  • 被动关闭方接收到ACK后进入到CLOSE状态
  • 主动关闭方等待2MSL后进入CLOSED状态
    在这里插入图片描述
    上图描述了连接和关闭时的状态转换。

2:TIME_WAIT状态

也称为2MSL等待状态。

该状态中TCP会等待两倍最大生存期(MSL)的时间。

等待2MSL比较合理的解释是:为了解决最后的ACK丢失的问题。(一个来回2MSL)

2MSL 的时间是从客户端接收到 FIN 后发送 ACK 开始计时的。如果在 TIME-WAIT时间内,因为客户端的 ACK 没有传输到服务端,客户端又接收到了服务端重发的FIN 报文,那么 2MSL 时间将重新计时。

按照规则:当TCP执行一个主动关闭并发送最终的ACK时,连接必须处于TIME_WAIT状态并且持续两倍于最大生命周期的时间。理由如下:

  • 保证连接的正确关闭:防止最终ACK丢失。如果最终ACK没有到达,会再次发送最终ACK。注意再次发送最终ACK是因为通信另一方重传了FIN。(否则被动关闭方会一直处于LAST_ACK状态)
  • 防止旧连接的报文段出现在下一个实例:等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文

3:静默时间

在本地与外地的IP地址、端口号都相同的情况下,2MSL状态能够防止新的连接将前一 个连接的延迟报文段解释成自身数据的状况。然而,上述方法只有在与处于2MSL等待状态的连接相关的主机未关闭的条件下才具有意义

如果一台与处于TIME_WAIT状态下的连接相关联的主机崩溃,然后在MSL内重新启动,并且使用与主机崩溃之前处于TIME_WAIT状态的连接相同的IP地址与端口号,那么 将会怎样处理呢?在上述情况下,该连接在主机崩溃之前产生的延迟报文段会被认为属于主机重启后创建的新连接。这种处理方式将不会考虑在主机重启之后新连接是如何选择初始序列号的

重新启动后,不会管初始序列号,只要四元组一样都会认为旧连接的报文段是本连接的?

静默时间

为了防止上述情况的发生,在崩溃或者重启后TCP协议应当在创建新的连接之前等待相当于一个MSL的时间。该段时间被称作静默时间

然而只有极少数实现遵循了这一点。因为绝大多数的主机在崩溃之后都需要超过一个MSL的时间才能重新启动。 此外,如果上层应用程序自身已采用了校验和或者加密手段,那么此类错误会很容易检测出来

4:FIN_WAIT2状态

FIN_WAIT2状态是某通信端已发送一个FIN并且得到另一端的ACK确认,就进入该状态,并且另一端进入CLOSE_WAIT状态。

然后等待另一端发送FIN报文(如果不是半关闭),如果一直没有发送FIN报文(另一端就会一直处于CLOSE_WAIT状态),那么主动一方就可能永远处于FIN_WAIT2状态。

如何防止进入FIN_WAIT2无限等待状态:如果负责主动关闭的应用程序执行的是一个完全关闭操作,而不是半关闭来指名还想接收数据,那么就会设置一个计时器。如果当计时器超时是连接是空闲的,那么TCP连接会直接转到CLOSED状态。

5:同时打开与关闭的状态转换

同时打开

在这里插入图片描述
同时打开只建立一个连接

通信双方几乎在同一时刻发送一个SYN报文段进入SYN_SEND状态。

之后接收到对方发来的SYN报文段会迁移到SYN_RCVD状态。

之后重新发送一个新的SYN并且确认之前收到的SYN。当通信双方收到了SYN与ACK进入ESTABLISHED状态

同时关闭

在这里插入图片描述

四:重置报文段

头部的RST字段置位时,代表该报文是一个重置报文段。一般来说当发现一个到达的报文段对于一个连接是不正确的时,就会发送一个重置报文段。重置报文段通常会导致连接的快速拆卸。

4.1:针对不存在端口的连接请求

通常情况下,当一个连接请求到达本地却没有相关进程在目的端口侦听时就会产生一个重置报文段。

4.2:终止一条连接

有序释放、终止释放

  • 从TCP断开连接的示意图可以知道,终止一条连接的正常方法是由通信一方发送一个FIN。这种方法有时也被称为有序释放。因为FIN是在之前所有排队数据都已发送后才被发送出去,通常不会出现丢失数据的情况
  • 然而在任何时刻,我们都可以通过发送一个重置报文段替代FIN来终止一条连接。这种方式有时被称作终止释放

终止释放可以为应用程序提供两大特性

  • 任何排队的数据都将被抛弃(不会等待数据发送完),一个重置报文段会被立即发送出去
  • 重置报文段的接收方会说明通信另一端采用了终止释放的方式而不是一次正常关闭

重置报文段不会令通信另一端做出任何响应,它不会被确认。接收到重置报文段的一端会终止连接并通知应用程序当前连接已被重置。

这样通常会造成“连接被另一端重置”的错误提示或者类似的消息

4.3:半开连接

与半关闭是不同的,半关闭会通知对方

  • 如果在未告知另一端的情况下通信的一端关闭或终止连接,那么就认为该条TCP连接 处于半开状态。 这种情况通常发生在通信一方的主机崩溃的情况下。只要不尝试通过半开连接传 输数据,正常工作的一端将不会检测出另一端已经崩溃
  • 产生半开连接的另一个共同原因是某一台主机的电源被切断而不是被正常关机。这种情 况可能发生于下面的例子中:某些个人电脑运行了远程登录客户端,并且在一天结束时关闭。 如果在电源被切断时没有数据在传输,那么服务器永远也不会知道该客户端已经消失(它可能还一直会认为该连接处于ESTABLISHED状态)。当第二天早晨用户回来,启动电脑并开 始一个新的会话时,服务器会启动一个新的服务进程。这样会导致服务器上有很多半开的TCP连接(在后面TCP保活机制会介绍一种方法,使TCP连接的一端能够利用TCP的keepalive选项 发现另一端已经消失)
  • 半开连接时,断开的一方对这个连接就没有记忆了,如果另一方(不知道对方断线了)向它发送数据,因为没有这个连接的记忆,TCP规定返回一个重置报文段移快速拆解这个连接。
    在这里插入图片描述

4.4:时间等待错误

如前文所述,设计TIME_WAIT状态的目的是允许任何受制于一条关闭连接的数据报被丢弃。在这段时期,等待的TCP通常不需要做任何操作,它只需要维持当前状态直到2MSL 的计时结束。然而,如果它在这段时期内接收到来自于这条连接的一些报文段,或是更加特 殊的重置报文段,它将会被破坏。这种情况被称作时间等待错误(TIME-WAIT Assassination TWA)
在这里插入图片描述

在上图的例子中,服务器完成了其在连接中的角色所承担的工作并清除了所有状态。客户端依然保持TIME_WAIT状态。当完成FIN交换,客户端的下一个序列号为K,而服务器的下一个序列号为L。最近到达的报文段是由服务器发送至客户端,它使用的序列号为L一100,包含的ACK号为K-200。当客户端接收到这个报文段时,它认为序列号与 ACK号的数值都是“旧”的。当接收到旧报文段时,TCP会发送一个ACK作为响应,其中包含了最新的序列号与ACK号(分别是K与L)。然而,当服务器接收到这个报文段以后,它没有关于这条连接的任何信息,因此发送一个重置报文段作为响应。这并不是服务器的问题,但它却会使客户端过早地从TIME_WAIT状态转移至CLOSED状态许多系统规定当处于TIME_WAIT状态时不对重置报文段做出反应,从而避免了上述问题

五:TCP服务器选项

大多数TCP服务器是并发的,当一个新的连接请求到达服务器时,服务器接受该连接,并调用一个新的进程或者线程来处理新的客户端。

TCP如何使用端口号,以及如何处理多个并发客户端事务没非常关注的问题。

1:TCP端口号

六:TCP超时与重传

1:序言

由于下层网络层可能出现丢失,重复或失序包的情况,TCP提供可靠数据传输服务。为保证数据传输的正确性,TCP重传其认为已丢失的包。

TCP拥有两套独立机制来完成重传,一个是基于时间,二是基于确认信息的构成。

第二种方法通常比第一种更高效

TCP在发送数据时会设置一个计时器,若至计时器超时仍未收到数据确认信息,则会引发相应的超时或基于计时器的重传操作,计时器超时称为重传超时RTO

另一种方式的重传称为快速重传,通常发生在没有时延的情况下

2:设置重传超时RTO

这样根据RTT设置RTO一直都是热点。算法很多。心无余力不足,跳过

3:基于计时器的重传

在设定计时器之前需要记录被计时的报文段序列号,如果即时接收到了该序号的ACK,那么就取消计时器。TCP连接在不断设置和取消计时器,如果数据没有丢失,就不会出现计时器超时。

一个窗口的数据一起设置计时器也是单独设置计时器,而不是打包?

若在连接设定的RTO内没有收到ACK,就会触发超时重传。

对于超时重传,TCP非常重视,它通过降低发送速率来对此进行快速响应。TCP的解决方式之一就是触发拥塞控制

4:快速重传

快速重传是基于接收端的反馈信息来引发重传,并不是由于计时器超时引起的,与超时重传相比,快速重传可以更加即时有效的修复丢包情况。

要理解快速重传,必须要理解当失序报文段到达服务端时,必须立即返回ACK(重复ACK),不能延时发送。这样能尽早的告诉发送端有失序报文段到达服务端,即接收端的缓存出现了空缺(表明在后续数据到达前出现了丢段)。但是光是重复ACK无法明确得知空缺的是哪一段。

当支持SACK时,即在SYN报文段中对方有允许选择确认选项,重复ACK通常也包含SACK信息,利用该信息可以知道空缺在哪里。

如果报文段仅是在网络中延迟,并没有丢失,可能也会出现重复ACK的情况,因此要等待合适阈值数量的重复ACK来决定数据是否丢失并触发快速重传。通常这个阈值为3.

概括:TCP发送端在观测到三个重复ACK后,就快速重传可能丢失的分组,而不必等到重传计时器超时。

快速重传的丢包通常与网络拥塞有关,因此快速重传也会触发拥塞控制机制

不采用SACK时,发送端每次只能获知一个空缺,所以修补的效率肯定没有SACK高。

超时重传和快速重传都会触发拥塞控制

5:带选择确认的重传

在出现空缺时,TCP发送端的任务是重传丢失的数据来填补空缺,但同时又要保证尽可能不要重传已经正确接收到的数据。

合理使用SACK可以快速实现空缺填补,且能减少不必要的重传。原因在于在一个RTT内可以获知多个空缺。当采用SACK时,一个ACK可以最多包含三个(或四个一般不会出现)告知失序数据的SACK信息。

每个ACK块代表接收端存储的失序数据的起始至最后一个序列号。

序列号32位,头尾两个就是8字节,再加上选项的种类和长度=8*n+2;看起来最多可以4个,但是,通常SACK会和TSOPT(时间戳)一起使用,因此额外需要十个字节(两个4字节的时间数值和2字节的选项种类和长度) ,这样就只能包含三个了。

这样就能够在一个RTT内通知发送端三个空缺,若不受拥塞控制的限制,利用SACK选项可在一个RTT时间填补3个空缺

主要优点就是一个RTT内可以填补多个空缺。

SACK接收端行为

接收端如何生成SACK选项 ?

会在多个SACK中重复序列信息,目的是防止SACK丢失。(丢失的SACK如果没有承载数据就不会被重传)

SACK发送端行为

通过接收到的SACK信息进行选择性重传。

SACK还可以不等待三次重复ACK就进行重传,为什么?

6:伪超时与伪重传

导致数据失序而重传的原因有两种
1:数据丢失
2:由于网络原因,新数据早于旧数据到达

伪重传: 即是该数据没有丢失,但是也进行了重传

其主要造成原因就是伪超时:过早判定超时。其他的因素像包失序(比如某一数据报因为网络原因被阻塞一段时间,晚于后传输的数据到达,就造成包失序),包重复,或者ACK丢失也可能导致该现象。

当实际RTT显著增长,超过当前RTO时,就可能出现伪超时。

DSACK,主要是为了判断何时的重传不是必要的

7:包失序与重复

包失序可能会产生快速重传。

如果一收到重复的ACK就进行重传,那么一定会导致许多不必要的重传。为了防止不必要的重传,重复ACK要达到一个阈值才进行快速重传。(能够很好的解决轻微失序,严重失序还是会被重传。严重失序不常见)

包重复到达不能忽略,要返回ACK。可能触发伪快速重传,但是如果使用了SACK就能够解决这个问题。

SACK可以有效解决包重复

8:重新组包

当TCP执行超时重传时并不需要完全重传相同的报文段。TCP允许执行重新组包,发送一个更大的报文段来提高性能。

但是不能大于MSS和MTU

七:TCP拥塞控制

7.1:引言

拥塞控制的基本方法是:当有理由认为网络即将进入拥塞状态(或者已经由于拥塞出现路由器丢包的情况)时减缓TCP传输。

什么是拥塞?
路由器无法处理高速率到达的流量而被迫丢弃信息的现象

7.2:TCP拥塞检测

针对丢包情况,TCP采取的首要措施是重传,包括快速重传和超时重传。但是当网络处于拥塞崩溃状态时,这就好比火上浇油。

通常的解决方案是:
当拥塞发生时,我们可以减缓TCP的发送端的发送速率;若拥塞情况有所缓解,可以检测和使用新的可用带宽。但是这在互联网中很难做到,因为对于TCP发送端来说,没有一个精确的方法去知晓中间路由器的状态。换言之,没有一个明确的信号告知拥塞状况已发生。典型的TCP只有在断定拥塞发生的情况下,才会采取相应的行动。

推断是否出现拥塞,通常是看是否有丢包情况发生。在TCP中,丢包也被用作判断拥塞发生与否的指标,用来衡量是否实施相应的响应措施(即以某种方式减缓发送)。TCP一直沿用这种方法

当然也出现了一些新的拥塞探测方法,包括时延测量和显示拥塞通知,使得TCP能在丢包发生前检测拥塞。

7.3:减缓TCP发送

一个亟待解决的问题就是,如何减缓TCP发送。

通知窗口:awnd:

之前我们就了解过,接收方通过设置一个通知窗口来调节发送方的速率,以不超过接收端的接收能力。

拥塞窗口:cwnd:

针对于中间网络,我们也可以·在发送方引入一个窗口控制变量,确保发送窗口大小不超过网络传输能力。这个窗口就是拥塞窗口。

那么通过这两个窗口大小变量,我们就可以确保发送窗口大小不超过接收端的接收能力和网络传输能力,即TCP发送端的发送速率等于接收速率和传输速率两者中较小值。

反应网络传输能力的变量成为拥塞窗口,记作cwnd。因此,发送端实际窗口大小是接收端通知窗口awnd拥塞窗口cwnd的较小者

7.4:一些经典算法

在一个连接建立之初,cwnd的初始值无法确定。而awnd的初始值只需要发送端与接收端交换一个数据报就能获得。

显而易见,获得cwnd最佳值的唯一方法是以越来越快的速率不断发送数据(cwnd增大的过程),直到出现数据包丢失(或网络拥塞)为止。

如下

发送端实际发送窗口大小:时接收端通知窗口和拥塞窗口cwnd的最小者。

如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。
在这里插入图片描述
TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、快重传、快恢复。

发送方需要维护一个叫做拥塞窗口(cwnd)的状态变量,注意拥塞窗口与发送方窗口的区别:拥塞窗口只是一个状态变量,实际决定发送方能发送多少数据的是发送方窗口。

为了便于讨论,做如下假设:

  • 接收方有足够大的接收缓存,因此不会发生流量控制;
  • 虽然 TCP 的窗口基于字节,但是这里设窗口的大小单位为报文段。
    在这里插入图片描述

1. 慢开始与拥塞避免

发送的最初执行慢开始,令 cwnd = 1,发送方只能发送 1 个报文段;当收到确认后,将 cwnd 加倍,因此之后发送方能够发送的报文段数量为:2、4、8 …

注意到慢开始每个轮次都将 cwnd 加倍,这样会让 cwnd 增长速度非常快,从而使得发送方发送的速度增长速度过快,网络拥塞的可能性也就更高。设置一个慢开始门限 ssthresh,当 cwnd >= ssthresh 时,进入拥塞避免,每个轮次只将 cwnd 加 1。

如果出现了超时,则令 ssthresh = cwnd / 2,然后重新执行慢开始。(但不小于2*SMSS)

2. 快重传与快恢复

在接收方,要求每次接收到报文段都应该对最后一个已收到的有序报文段进行确认。例如已经接收到 M1 和 M2,此时收到 M4,应当发送对 M2 的确认。

在发送方,如果收到三个重复确认,那么可以知道下一个报文段丢失,此时执行快重传,立即重传下一个报文段。例如收到三个 M2,则 M3 丢失,立即重传 M3。

在这种情况下,只是丢失个别报文段,而不是网络拥塞。因此执行快恢复,令 ssthresh = cwnd / 2 ,cwnd = ssthresh,注意到此时直接进入拥塞避免。

慢开始和快恢复的快慢指的是 cwnd 的设定值,而不是 cwnd 的增长速率。慢开始 cwnd 设定为 1,而快恢复 cwnd 设定为 ssthresh。

在这里插入图片描述

八:TCP保活机制

是一种在不影响数据流内容的情况下探测对方的方式。它是由一个保活计时器实现的。当计时器被激发, 连接端将发送一个保活探测(简称保活)报文 , 另一端接收报文的同时会发送一个ACK作为响应。

保活功能在默认情况下是关闭的,TCP连接的任何一端都可以请求打开这一功能。保活功能可以被设置在连接的一端、两端,或者两端都没有。

但是保活机制也存在一定的争议:保活机制是一个可选择激活的功能。它可能会导致一个好的连接由于两端系统之间网络的短暂断开而终止。
参考文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值