程序员TCP 基础知识汇编_第1页
程序员TCP 基础知识汇编_第2页
程序员TCP 基础知识汇编_第3页
程序员TCP 基础知识汇编_第4页
程序员TCP 基础知识汇编_第5页
已阅读5页,还剩29页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

程序员TCP基础知识

这是一篇详细介绍TCP各种特点的文章,内容主要包括TCP三次握手和

四次挥手细节问题、TCP状态之间的转换、TCP超时和重传、关于TCP包

失序和重复问题、TCP的数据流与窗口管理、TCP的拥塞控制,思维导图

如下。

TCP状态转换TIME_WAIT状态

包失序

TCP是一种面向连接的单播协议,在TCP中,并不存在多播、广播的这

种行为,因为TCP报文段中能明确发送方和接受方的IP地址。

在发送数据前,相互通信的双方(即发送方和接受方)需要建立一条连接,

在发送数据后,通信双方需要断开连接,这就是TCP连接的建立和终止。

TCP连接的建立和终止

如果你看过我之前写的关于网络层的一篇文章,你应该知道TCP的基本元

素有四个:即发送方的IP地址、发送方的端口号、接收方的IP地址、

接收方的端口号。而每一方的IP+端口号都可以看作是一个套接字,套接

字能够被唯一标示。套接字就相当于是门,出了这个门,就要进行数据传

输了。

TCP的连接建立->终止总共分为三个阶段

下面我们所讨论的重点也是集中在这三个层面。

下图是一个非常典型的TCP连接的建立和关闭过程,其中不包括数据传输

的部分。

hrcp建立连接-三次握手

客户端主机服务器主机

i.

服务端进程准备好接收来自外部的TCP连接,一般情况下是调用bind、

listen、socket三个函数完成。这种打开方式被认为是被动打开(passive

open)o然后服务端进程处于LISTEN状态,等待客户端连接请求。

客户端通过connect发起主动打开(activeopen),向服务器发出连接请求,

请求中首部同步位SYN=1,同时选择一个初始序号sequence,简写seq

=xoSYN报文段不允许携带数据,只消耗一个序号。此时,客户端进

入SYN-SEND状态。

3.

服务器收到客户端连接后,,需要确认客户端的报文段。在确认报文段中,

把SYN和ACK位都置为1。确认号是ack=x+1,同时也为自己选择

一个初始序号seq=y。这个报文段也不能携带数据,但同样要消耗掉一个

序号。此时,TCP服务器进入SYN-RECEIVED(同步收到)状态。

客户端在收到服务器发出的响应后,还需要给出确认连接。确认连接中的

ACK置为1,序号为seq=x+1,确认号为ack=y+1。TCP规定,

这个报文段可以携带数据也可以不携带数据,如果不携带数据,那么下一

个数据报文段的序号仍是seq=x+1o这时,客户端进入ESTABLISHED

(已连接)状态

服务器收到客户的确认后,也进入ESTABLISHED状态。

这是一个典型的三次握手过程,通过上面3个报文段就能够完成一个

TCP连接的建立。三次握手的的目的不仅仅在于让通信双方知晓正在建立

一个连接,也在于利用数据包中的选项字段来交换一些特殊信息,交换初

始序列号。

一般首个发送SYN报文的一方被认为是主动打开一个连接,而这一方通常也被称为客户

端。而SYN的接收方通常被称为服务端,它用于接收这个SYN,并发送下面的SYN,

因此这种打开方式是被动打开。

TCP建立一个连接需要三个报文段,释放一个连接却需要四个报文段。

rep断开连接-四次挥手

数据传输结束后,通信的双方可以释放连接。数据传输结束后的客户端主

机和服务端主机都处于ESTABLISHED状态,然后进入释放连接的过程。

客户端主机服务器主机

主动关闭被动关闭

数据传输

等待

2MSL

CLOSED

TCP断开连接需要历经的过程如下

客户端应用程序发出释放连接的报文段,并停止发送数据,主动关闭TCP

连接。客户端主机发送释放连接的报文段,报文段中首部FIN位置为1,

不包含数据,序列号位seq=u,此时客户端主机进入FIN-WAIT-1(终止等

待1)阶段。

服务器主机接受到客户端发出的报文段后,即发出确认应答报文,确认应

答报文中ACK=1,生成自己的序号位seq=v,ack=u+1,然后服务器

主机就进入CLOSE-WAIT(关闭等待)状态。

3.

客户端主机收到服务端主机的确认应答后,即进入FIN-WAIT-2(终止等待

2)的状态。等待客户端发出连接释放的报文段。

这时服务端主机会发出断开连接的报文段,报文段中ACK=1,序歹U号seq

=v,ack=u+1,在发送完断开请求的报文后,服务端主机就进入

TLAST-ACK(最后确认)的阶段。

客户端收到服务端的断开连接请求后,客户端需要作出响应,客户端发出

断开连接的报文段,在报文段中,ACK=1,序列号seq=u+1,因为客

户端从连接开始断开后就没有再发送数据,ack=v+1,然后进入

到TIME-WAIT(时间等待)状态,请注意,这个时候TCP连接还没有释放。

必须经过时间等待的设置,也就是2MSL后,客户端才会进入CLOSED状

态,时间MSL叫做最长报文段寿命(MaximumSegmentLifetime)。

服务端主要收到了客户端的断开连接确认后,就会进入CLOSED状态。

因为服务端结束TCP连接时间要比客户端早,而整个连接断开过程需要发

送四个报文段,因此释放连接的过程也被称为四次挥手。

TCP连接的任意一方都可以发起关闭操作,只不过通常情况下发起关闭连

接操作一般都是客户端。然而,一些服务器比如Web服务器在对请求作

出相应后也会发起关闭连接的操作。TCP协议规定通过发送一个FIN报

文来发起关闭操作。

所以综上所述,建立一个TCP连接需要三个报文段,而关闭一个TCP连

接需要四个报文段。TCP协议还支持一种半开启(half-open)状态,虽然这

种情况并不多见。

CP半开启

TCP连接处于半开启的这种状态是因为连接的一方关闭或者终止了这个

TCP连接却没有通知另一方,也就是说两个人正在微信聊天,cxuan你下

线了你不告诉我,我还在跟你侃八卦呢。此时就认为这条连接处于半开启

状态。这种情况发生在通信中的一方处于主机崩溃的情况下,你XXX的,

我电脑死机了我咋告诉你?只要处于半连接状态的一方不传输数据的话,

那么是无法检测出来对方主机已经下线的。

另外一种处于半开启状态的原因是通信的一方关闭了主机电源而不是正常

关机。这种情况下会导致服务器上有很多半开启的TCP连接。

rep半关闭

既然TCP支持半开启操作,那么我们可以设想TCP也支持半关闭操作。

同样的,TCP半关闭也并不常见。TCP的半关闭操作是指仅仅关闭数据流

的一个传输方向。两个半关闭操作合在一起就能够关闭整个连接。在一般

情况下,通信双方会通过应用程序互相发送FIN报文段来结束连接,但是

在TCP半关闭的情况下,应用程序会表明自己的想注:"我己经完成了数

据的发送发送,并发送了一个FIN报文段给对方,但是我依然希望接收来

自对方的数据直到它发送一个FIN报文段给我"。下面是一个TCP半关闭

的示意图。

客户端主机服务器主机

解释一下这个过程:

首先客户端主机和服务器主机一直在进行数据传输,一段时间后,客户端

发起了FIN报文,要求主动断开连接,服务器收到FIN后,回应ACK,

由于此时发起半关闭的一方也就是客户端仍然希望服务器发送数据,所以

服务器会继续发送数据,一段时间后服务器发送另外一条FIN报文,在客

户端收到FIN报文回应ACK给服务器后,断开连接。

TCP的半关闭操作中,连接的一个方向被关闭,而另一个方向仍在传输数据直到它被关闭

为止。只不过很少有应用程序使用这一特性。

同时打开和同时关闭

还有一种比较非常规的操作,这就是两个应用程序同时主动打开连接。虽

然这种情况看起来不太可能,但是在特定的安排下却是有可能发生的。我

们主要讲述这个过程。

通信双方在接收到来自对方的SYN之前会首先发送一个SYN,这个场景

还要求通信双方都知道对方的IP地址+端口号。

下面是同时打开的例子

通信一方通信另一方

数据传输

如上图所示,通信双方都在收到对方报文前主动发送了SYN报文,都在

收到彼此的报文后回复了一个ACK报文。

一个同时打开过程需要交换四个报文段,比普通的三次握手增加了一个,

由于同时打开没有客户端和服务器一说,所以这里我用了通信双方来称呼。

像同时打开一样,同时关闭也是通信双方同时提出主动关闭请求,发送FIN

报文,下图显示了一个同时关闭的过程。

通信一方通信另一方

主动关闭主动关闭

同时关闭过程中需要交换和正常关闭相同数量的报文段,只不过同时关闭

不像四次挥手那样顺序进行,而是交叉进行的。

聊一聊初始序列号

也许是我上面图示或者文字描述的不专业,初始序列号它是有专业术语表

示的,初始序歹ij号的英文名称是Initialsequencenumbers(ISN),所以我

们上面表示的seq=v,其实就表示的ISNo

在发送SYN之前,通信双方会选择一个初始序列号。初始序列号是随机

生成的,每一个TCP连接都会有一个不同的初始序列号。RFC文档指出

初始序列号是一个32位的计数器,每4us(微秒)+1。因为每个TCP

连接都是一个不同的实例,这么安排的目的就是为了防止出现序列号重叠

的情况。

当一个TCP连接建立的过程中,只有正确的TCP四元组和正确的序列号

才会被对方接收。这也反应了TCP报文段容易被伪造的脆弱性,因为只

要我伪造了一个相同的四元组和初始序列号就能够伪造TCP连接,从而打

断TCP的正常连接,所以抵御这种攻击的一种方式就是使用初始序列号,

另外一种方法就是加密序列号。

TCP状态转换

我们上面聊到了三次握手和四次挥手,提到了一些关于TCP连接之间的状

态转换,那么下面我就从头开始和你好好梳理一下这些状态之间的转换。

首先第一步,刚开始时服务器和客户端都处于CLOSED状态,这时需要

判断是主动打开还是被动打开,如果是主动打开,那么客户端向服务器发

送SYN报文,此时客户端处于SYN-SEND状态,SYN-SEND表示发送连

接请求后等待匹配的连接请求,服务器被动打开会处于USTEN状态,用

于监听SYN报文。如果客户端调用了close方法或者经过一段时间没有

操作,就会重新变为CLOSED状态,这一步转换图如下

'、、、开始

这里有个疑问,为什么处于LISTEN状态下的客户端还会发送SYN变为SYN_SENT

状态呢?

知乎看到了车小胖大佬的回答,这种情况可能出现在FTP中,LISTEN,

SYN_SENT是因为这个连接可能是由于服务器端的应用有数据发送给客

户端而触发的,客户端被动接受连接,连接建立后,开始传输文件。也就

是说,处于LISTEN状态的服务器也是有可能发送SYN报文的,只不过

这种情况非常少见。

处于SYN_SEND状态的服务器会接收SYN并发送SYN和ACK转换

成为SYN_RCVD状态,同样的,处于LISTEN状态的客户端也会接收

SYN并发起SYN和ACK转换为SYN_RCVD状态。如果处于

SYN_RCVD状态的客户端收到RST就会变为LISTEN状态。

这两张图一起看会比较好一些。

这里需要解释下什么是RST

这里有一种情况是当主机收到TCP报文段后,其IP和端口号不匹配的情

况。假设客户端主机发送一个请求,而服务器主机经过IP和端口号的判断

后发现不是给这个服务器的,那么服务器就会发出一个RST特殊报文段给

客户端。

客户端主机服务器主机

因此,当服务端发送一个RST特殊报文段给客户端的时候,它就会告诉客

户端没有匹配的套接字连接,请不要再继续发送了。

RST:(Resettheconnection)用于复位因某种原因引起出现的错误连接,

也用来拒绝非法数据和请求。如果接收到RST位时候,通常发生了某些

错误。

上面没有识别正确的IP端口是一种导致RST出现的情况,除此之外,

RST还可能由于请求超时、取消一个已存在的连接等出现。

位于SYN_RCVD的服务器会接收ACK报文,SYN_SEND的客户端会

接收SYN和ACK报文,并发送ACK报文,由此,宣户端和服务器之间

的连接就建立了。

客户靖主机艇务a主机

被动打开

这里还要注意一点,同时打开的状态我在上面没有刻意表示出来,实际上,

在同时打开的情况下,它的状态变化是这样的。

一端主机另一端主机

主动打开

为什么会是这样呢?因为你想,在同时打开的情况下,两端主机都发起

SYN报文,而主动发起SYN的主机会处于SYN-SEND状态,发送完成

后,会等待接收SYN和ACK,在双方主机都发送了SYN+ACK后,

双方都处于SYN-RECEIVED(SYN-RCVD)状态,然后等待SYN+ACK

的报文到达后,双方就会处于ESTABLISHED状态,开始传输数据。

好了,到现在为止,我给你叙述了一下TCP连接建立过程中的状态转换,

现在你可以泡一壶茶喝点水,等着数据传输了。

好了,现在水喝够了,这时候数据也传输完成了,数据传输完成后,这条TCP

连接就可以断开了。

现在我们把时钟往前拨一下,调整到服务端处于SYN_RCVD状态的时亥(),

因为刚收到了SYN包并发送了SYN+ACK包,此帚服务端很开心,但

是这时,服务端应用进程关闭了,然后应用进程发了一个FIN包,就会让

服务器从SYNRCVD->FINWAIT1状态。

、开始客户端主机服务器主机

・动关册

然后把时钟调到现在,客户端和服务器现在已经传输完数据了,此时客户

端发送了一条FIN报文希望断开连接,此时客户端也会变

为FIN_WAIT_1状态,对于服务器来说,它接收到了FIN报文段并回复了

ACK才营文,露会从ESTABLISHED->CLOSE_WAIT状态。

服务主机

、、开始客户Ml主机H

主动关用・动关册

发送数据

USTENSYN_SENT

发送S?N

接收SYN

接收SYN

接收RST发送SYN

发送SYN和ACK

ACK■

同时打开

fcYN_RCV(l

收SYN和ACK

发送ACK

接唉APK

Close

送:FIN

发送FIN

mLOSE_WAITLAST.ACK

Close接收:FIN

发送:FIN发送:ACK

接收ACK

FIN_WA!T_2

接收Fl4

发送ACKCLOSING

位于CLOSE_WAIT状态的服务端会发送FIN报文,然后把自己置于

LAST_ACK或态。处于FIN_WAIT_1的客户端接收ACK消息就会变为

FIN_WAIT_2状态。

这里需要先解释一下CLOSING这个状态,FIN_WAIT1->CLOSING的转换比较特殊

CLOSING这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕

见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收

到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是

CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,

反而却也收到了对方的FIN报文。

什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是

如果双方在同时关闭一个链接的话,那么就出现了同时发送FIN报文的情

况,也即会出现CLOSING状态,表示双方都正在关闭连接。

FIN_WAIT_2状态的客户端接收服务端主机发送的FIN+ACK消息,并

发瘪ACK响应后,会变为TIME_WAIT状态。处于CLOSE_WAIT的客

户端发送FIN会处于LAST_ACK状态。

这里不少图和博客虽然在图上画的是FIN+ACK报文后才会处于LAST_ACK状态,但

是描述的时候,一般通常只对于FIN进行描述.也就是说CLOSE_WAIT发送FIN才会

处于LASTACK状态。

'、、开始

M

所以这里FIN_WAIT_1->TIME_WAIT的状态也就是接收FIN和ACK

并发送ACK之后,客户端处于防状态。

然后位于CLOSINIG状态的客户端这时候还有ACK接收的话,会继续处

于TIME_WAIT状态,可以看到,TIME_WAIT状态相当于是客户端在关

闭前的最诘一个状态,它是一种主动关闭的状态;而LAST_ACK是服务

端在关闭前的最后一个状态,它是一种被动打开的状态。

上面有几个状态比较特殊,这里我们详细解释下。

IME_WAIT状态

通信双方建立TCP连接后,主动关闭连接的一方就会进入TIME_WAIT

状态。TIME_WAIT状态也称为2MSL的等待状态。在这个状态下,TCP将

会等待最大段生存期(MaximumSegmentLifetime,MSL)时间的两倍。

这里需要解释下MSL

MSL是TCP段期望的最大生存时间,也就是在网络中存在的最长时间。

这个时间是有限制的,因为我们知道TCP是依靠IP数据段来进行传输

的,IP数据报中有TTL和跳数的字段,这两个字段决定了IP的生存时

间,一般情况下,TCP的最大生存时间是2分钟,不过这个数值是可以

修改的,根据不同操作系统可以修改此值。

基于此,我们来探讨TIME_WAIT的状态。

当TCP执行一个主动关闭并发送最终的ACK时,TIME_WAIT应该以2

*最大生存时间存在,这样就能够让TCP重新发送最终前ACK以避免出

现丢失的情况。重新发送最终的ACK并不是因为TCP重传了ACK,而

是因为通信另一方重传了FIN,客户端经常会发送FIN,因为它需要ACK

的响应才能够关闭连接,如果生存时间超过了2MSL的话,客户端就会发

送RST,使服务端出错。

TCP超时和重传

没有永远不出错误的通信,这句话表明着不管外部条件多么完备,永远都

会有出错的可能。所以,在TCP的正常通信过程中,也会出现错误,这种

错误可能是由于数据包丢失引起的,也可能是由于数据包重复引起的,甚

至可能是由于数据包失序引起的。

TCP的通信过程中,会由TCP的接收端返回一系列的确认信息来判断是

否出现错误,一旦出现丢包等情况,TCP就会启动重传操作,重传尚未确

认的数据。

TCP的重传有两种方式,一种是基于时间,一种是基于确认信息、,一般通

过确认信息要比通过时间更加高效。

所以从这点就可以看出,TCP的确认和重传,都是基于数据包是否被确认为前提的。

TCP在发送数据时会设置一个定时器,如果在定时器指定的时间内未收到

确认信息,那么就会触发相应的超时或者基于计时器的重传操作,计时器

超时通常被称为重传超时(RTO)。

但是有另外一种不会引起延迟的方式,这就是快速重传。

TCP在每次重传一次报文后,其重传时间都会加倍,这种"间隔时间加倍"

被称为二进制指数补偿(binaryexponentialbackoff)。等到间隔时间加倍

到15.5min后,客户端会显示

[Connectionclosedbyforeignhost.

TCP拥有两个阈值来决定如何重传一个报文段,这两个阈值被定义在

RFC[RCF1122]中,第一个阈值是R1,它表示愿意尝试重传的次数,阈

值R2表示TCP应该放弃连接的时间。R1和R2应至少设为三次重传和

100秒放弃TCP连接。

这里需要注意下,对连接建立报文SYN来说,它的R2至少应该设置为3分钟,但是

在不同的系统中,R1和R2值的设置方式也不同。

在Linux系统中,R1和R2的值可以通过应用程序来设置,或者是修

改net.ipv4.tcp_retries1和net.ipv4.tcp_retries2的值来设置。变量值

就是重传次数。

tcp_retries2的默认值是15,这个充实次数的耗时大约是13-30分钟,

这只是一个大概值,最终耗时时间还要取决于RTO,也就是重传超时时

间。tcp_retries1的默认值是3。

对于SYN段来说,net.ipv4.tcp_syn_retries和

net.ipv4.tcp_synack_retries这两个值限制了SYN的重传次数,默认是

5,大约是180秒。

Windows操作系统下也有R1和R2变量,它们的值被定义在下方的注册

表中

HKLM\System\CurrentControlSet\Services\Tcpip\Parameters・

HKLM\System\CurrentControlSet\Services\Tcpip6\Parameters|

其中有一个非常重要的变量就是TcpMaxDataRetransmissions,这个

TcpMaxDataRetransmissions对应Linux中的tcp_retries2变量,默认

值是5o这个值的意思表示的是TCP在现有连接上未确认数据段的次数。

快速重传

我们上面提到了快速重传,实际上快速重传机制是基于接收端的反馈信息

来触发的,它并不受重传计时器的影响。所以与超时重传相比,快速重传

能够有效的修复丢包情况。当TCP连接的过程中接收端出现乱序的报文

(比如2-4-3)到达时,TCP需要立刻生成确认消息,这种确认消息也

被称为重复ACKo

当失序报文到达时,重复ACK要做到立刻返回,不允许延迟发送,此举

的目的是要告诉发送方某段报文失序到达了,希望发送方指出失序报文段

的序列号。

还有一种情况也会导致重复ACK发给发送方,那就是当前报文段的后续

报文发送至接收端,由此可以判断当前发送方的报文段丢失或者延迟到达。

因为这两种情况导致的后果都是接收方没有收到报文,但是我们却无法判

断到底是报文段丢失还是报文段没有送达。因此TCP发送端会等待一定数

目的重复ACK被接受来决定数据是否丢失并触发快速重传。一般这个判

断的数量是3,这段文字表述可能无法清晰理解,我们举个例子。

1

ACK2

2

3

ACK2

4

ACK2

5

ACK2

ACK6

如上图所示,报文段1成功接收并被确认为ACK2,接收端的期待序号为

2,当报文段2丢失后,报文段3。失序到达,但是与接收端的期望不匹

配,所以接收端会重复发送冗余ACK2o

这样,在超时重传定时器到期之前,接收收到连续三个相同的ACK后,

发送端就知道哪个报文段丢失了,于是发送方会重发这个丢失的报文段,

这样就不用等待重传定时器的到期,大大提高了效率。

SACK

在标准的TCP确认机制中,如果发送方发送了0-10000序号之间的数

据,但是接收方只接收到了0-1000,3000-10000之间的数据,而1000

-3000之间的数据没有到达接收端,此时发送方会重传1000-10000之

间的数据,实际上这是没有必要的,因为3000后面的数据已经被接收了。

但是发送方无法感知这种情况的存在。

如何避免或者说解决这种问题呢?

为了优化这种情况,我们有必要让客户端知道更多的消息,在TCP报文段

中,有一个SACK选项字段,这个字段是一种选择性确认(selective

acknowledgment)机制,这个机制能告诉TCP客户端,用我们的俗语来

解释就是:“我这里最多允许接收1000之后的报文段,但是我却收到了

3000-10000的报文段,请给我1000-3000之间的报文段”。

但是,这个选择性确认机制的是否开启还受一个字段的影响,这个字段就

是SACK允许选项字段,通信双方在SYN段或者SYN+ACK段中添加

SACK允许选项字段来通知对端主机是否支持SACK,如果双方都支持的

话,后续在SYN段中就可以使用SACK选项了。

这里需要注意下:SACK选项字段只能出现在SYN段中.

伪超时和重传

在某些情况下,即使没有出现报文段的丢失也可能会引发报文重传。这种

重传行为被称为伪重传(spuriousretransmission),这种重传是没有必要

的,造成这种情况的因素而能是由于伪超时(spurioustimeout),伪超时的

意思就是过早的判定超时发生。造成伪超时的因素有很多,比如报文段失

序到达,报文段重复,ACK丢失等情况。

检测和处理伪超时的方法有很多,这些方法统称为检测算法和响应算法。

检测算法用于判断是否出现了超时现象或出现了计时器的重传现象。一旦

出现了超时或者重传的情况,就会执行响应算法撤销或者减轻超时带来的

影响,下面是几种算法,此篇文章暂不深入这些实现细节

重复SACK扩展-DSACK

Eifel检测算法

前移RTO恢复-F-RTO

Eifel响应算法

包失序和包重复

上面我们讨论的都是TCP如何处理丢包的问题,我们下面来讨论一下包失

序和包重复的问题。

包失序

数据包的失序到达是互联网中极其容易出现的一种情况,由于IP层并不能

保证数据包的有序性,每个数据包的发送都可能会选择当前情况传输速度

最快的链路,所以很有可能出现发送了A->B->C的三个数据包,到达

接收端的数据包顺序是C->A->B或者B->C->A等等。这就是包失

序的一种现象。

在包传输中,主要分为两种链路:正向链路(SYN)和反向链路(ACK)

如果失序发生在正向链路,TCP是无法正确判断数据包是否丢失的,数据

的丢失和失序都会导致接收端收到无序的数据包,造成数据之间的空缺。

如果这种空缺不够大的话,这种情况影响不大;但是如果空缺比较大的话,

可能会导致伪重传。

如果失序发生在反向链路,就会使TCP的窗口前移,然后收到重复而应该

被丢弃的ACK,导致发送端出现不必要的流量突发,影响可用网络带宽。

回到我们上面讨论的快速重传,由于快速重传是根据重复ACK推断出现

丢包而启动的,它不用等到重传计时器超时。由于TCP接收端会对接收到

的失序报文立刻返回ACK,所以网络中任何一个失序到达的报文都可能会

造成重复ACK。假设一旦收到ACK,就会启动快速重传机制,当ACK数

量激增,就会导致大量不必要的重传发生,所以快速重传应该达到重复阈

值(dupthresh)再触发。但是在互联网中,严重的失序并不常见,因此

dupthresh的值可以设置的尽量小,一般来说3就能处理绝大部分情况。

包重复

包重复也是互联网中出现很少的一种情况,它指的是在网络传输过程中,

包可能会出现传输多次的情况,当重传生成时,TCP可能会出现混淆。

包的重复可以使接收端生成一系列的重复ACK,这种情况可以使用SACK

协商来解决。

TCP数据流和窗口管理

我们在40张图带你搞懂TCP和UDP这篇文章中知道了可以使用滑动

窗口来实现流量控制,也就是说,客户端和服务器可以相互提供数据流信

息的交换,数据流的相关信息主要包括报文段序列号、ACK号和窗口大小。

图中的两个箭头表示数据流方向,数据流方向也就是TCP报文段的传输方

向。可以看到,每个TCP报文段中都包括了序列号、ACK和窗口信息,

可能还会有用户数据。TCP报文段中的窗口大小表示接收端还能够接收的

缓存空间的大小,以字节为单位。这个窗口大小是一种动态的,因为无时

无刻都会有报文段的接收和消失,这种动态调整的窗口大小我们称之为滑

动窗口,下面我们就来具体认识一下滑动窗口。

滑动窗口

TCP连接的每一端都可以发送数据,但是数据的发送不是没有限制的,实

际上,TCP连接的两端都各自维护了一个发送窗口结构(sendwindow

structure)和接收窗口结构(receivewindowstructure),这两个窗口结

构就是数据发送的限制。

发送方窗口

下图是一个发送方窗口的示例。

发送窗口结构

窗口移动方向

在这幅图中,涉及滑动窗口的四种概念:

已经发送并确认的报文段:发送给接收方后,接收方回回复ACK来对报

文段进行响应,图中标注绿色的报文段就是已经经过接收方确认的报文段。

已经发送但是还没确认的报文段:图中绿色区域是经过接收方确认的报文

段,而浅蓝色这段区域指的是已经发送但是还未经过接收方确认的报文段。

等待发送的报文段:图中深蓝色区域是等待发送的报文段,它属于发送窗

口结构的一部分,也就是说,发送窗口结构其实是由已发送未确认+等待

发送的报文段构成。

窗口滑动时才能发送的报文段:如果图中的[4,9]这个集合内的报文段发送

完毕后,整个滑动窗口会向右移动,图中橙色区域就是窗口右移时才能发

送的报文段。

滑动窗口也是有边界的,这个边界是Leftedge和Rightedge,Leftedge是

窗口的左边界,Rightedge是窗口的右边界。

当Leftedge向右移动而Rightedge不变时,这个窗口可能处于close关

闭状态。随着已发送的数据逐渐被确认从而导致窗口变小时,就会发生这

种情况。

发送窗口结构

窗口移动方向

-2

234567891011

此时没有左右边界

窗口close

当Rightedge向右移动时,窗口会处于open打开状态,允许发送更多的

数据。当接收端进程读取缓冲区数据,从而使缓冲区接收更多数据时,就

会处于这种状态。

2345678910

此时没有左右边界

窗口close发送窗口结构

:已经发送但是:等待发送

发送并确认的

:还没确认:的报文段

报文段

:的报文段:

|窗口移动方向

LeftedgeRightedge

右边界向右移动

窗口open

还可能会发生Rightedge向左移动的情况,会导致发送并确认的报文段变

小,这种情况被称为糊涂窗口综合症,这种情况是我们不愿意看到的。出

现糊涂窗口综合症时,通信双方用于交换的数据段大小会变小,而网络固

定的开销却没有变化,每个报文段中有用数据相对于头部信息的比例较小,

导致传输效率非常低。

这就相当于之前你明明有能力花一天时间写完一个复杂的页面,现在你花

了一天的时间却改了一个标题的bug,大材小用。

每个TCP报文段都包含ACK号和窗口通告信息,所以每当收到响应时,

TCP接收方都会根据这两个参数调整窗口结构。

TCP滑动窗口的Leftedge永远不可能向左移动,因为发送并确认的报文

段永远不可能被取消,就像这世界上没有后悔药一样。这条边缘是由另一

段发送的ACK号控制的。当ACK标号使窗口向右移动但是窗口大小没

有改变时,则称该窗口向前滑动。

如果ACK的编号增加但是窗口通告信息随着其他ACK的到达却变小

了,止匕时Leftedge会接近Rightedge«当Leftedge和Rightedge重

合时,此时发送方不会再传输任何数据,这种情况被称为零窗口。此时TCP

发送方会发起窗口探测,等待合适的时机再发送数据。

接收方窗口

接收方也维护了一个窗口结构,这个窗口要比发送方的简单很多。这个窗

口记录了己经接收并确认的数据,以及它能够接收的最大序列号。接收方

的窗口结构不会存储重复的报文段和ACK,同时接收方的窗口也不会记录

不应该收到的报文段和ACKo下面是TCP接收方的窗口结构。

接收方窗口结构

已经接收不能接收的

接收后会进行保存的报文段

并确认的报文段

报文段

LeftedgeRightedge

与发送端的窗口一样,接收方窗口结构也维护了一个Leftedge和Right

edge。位于Leftedge左边的被称为已经接收并确认的报文段,位于Right

edge右边的被称为不能接收的报文段。

对于接收端来说,到达序列号小于Leftefge的被认为是已经重复的数据,

需要丢弃。超过Rightedge的被认为超出处理范围。只有当到达的报文段

等于Leftedge时,数据才不会被丢弃,窗口才能够向前滑动。

接收方窗口结构也会存在零窗口的情况,如果某个应用进程消耗数据很慢,

而TCP发送方却发送了大量的数据给接收方,会造成TCP缓冲区溢出,

通告发送方不要再发送数据了,但是应用进程却以非常慢的速度消耗缓冲

区的数据(比如1字节),就会告诉接收端只能发送一个字节的数据,这

个过程慢慢持续,造成网络开销大,效率很低。

我们上面提到了窗口存在Leftedge=Rightedge的情况,此时被称为零窗口,下面我们

就来具体研究一下零窗口。

零窗口

TCP是通过接收端的窗口通告信息来实现流量控制的。通告窗口告诉了

TCP,接收端能够接收的数据量。当接收方的窗口变为0时,可以有效

的阻止发送端继续发送数据。当接收端重新获得可用空间时,它会给发送

端传输一个窗口更新告知自己能够接收数据了。窗口更新一般是纯

ACK,即不带任何数据。但是纯ACK不能保证一定会到达发送端,于是

需要有相关的措施能够处理这种丢包。

如果纯ACK丢失的话,通信双方就会一直处于等待状态,发送方心想拉

垮的接收端怎么还让我发送数据!接收端心想天杀的发送方怎么还不发数

据!为了防止这种情况,发送方会采用一个持续计时器来间歇性的查询接

收方,看看其窗口是否已经增长。持续计时器会触发窗口探测,强制要求

接收方返回带有更新窗口的ACKo

窗口探测包含一个字节的数据,采用的是TCP丢失重传的方式。当TCP

持续计时器超时后,就会触发窗口探测的发送。一个字节的数据能否被接

收端接收,还要取决于其缓冲区的大小。

拥塞控制

有了TCP的窗口控制后,使计算机网络中两个主机之间不再是以单个数据

段的形式发送了,而是能够连续发送大量的数据包。然而,大量数据包同

时也伴随着其他问题,比如网络负载、网络拥堵等问题。TCP为了防止这

类问题的出现,使用了拥塞控制机制,拥塞控制机制会在面临网络拥塞时

遏制发送方的数据发送。

拥塞控制主要有两种方法

端到端的拥塞控制:因为网络层没有为运输层拥塞控制提供显示支持。所以

即使网络中存在拥塞情况,端系统也要通过对网络行为的观察来推断。TCP

就是使用了端到端的拥塞控制方式。IP层不会向端系统提供有关网络拥塞

的反馈信息。那么TCP如何推断网络拥塞呢?如果超时或者三次冗余确

认就被认为是网络拥塞,TCP会减小窗口的大小,或者增加往返时延来避

免。

网络辅助的拥塞控制:在网络辅助的拥塞控制中,路由器会向发送方提供关

于网络中拥塞状态的反馈。这种反馈信息就是一个比特信息,它指示链路

中的拥塞情况。

下图描述了这两种拥塞控制方式

TCP拥塞控制

如果你看到这里,那我就暂定认为你了解了TCP实现可靠性的基础了,那

就是使用序号和确认号。除此之外,另外一个实现TCP可靠性基础的就是

TCP的拥塞控制。如果说

TCP所采用的方法是让每一个发送方根据所感知到的网络的拥塞程度来限

制发出报文段的速率,如果TCP发送方感知到没有什么拥塞,则TCP发

送方会增加发送速率;如果发送方感知沿着路径有阻塞,那么发送方就会

降低发送速率。

但是这种方法有三个问题

1.

TCP发送方如何限制它向其他连接发送报文段的速率呢?

2.

3.

一个TCP发送方是如何感知到网络拥塞的呢?

4.

5.

当发送方感知到端到端的拥塞时,采用何种算法来改变其发送速率呢?

6.

我们先来探讨一下第一个问题,TCP发送方如何限制它向其他连接发送报

文段的速率呢?

我们知道TCP是由接收缓存、发送缓存和变量(LastByteRead,rwnd,等)

组成。发送方的TCP拥塞控制机制会跟踪一个变量,即拥塞窗口

(congestionwindow)的变量,拥塞窗口表示为cwnd,用于限制TCP在

接收到ACK之前可以发送到网络的数据量。而接收窗口(rwnd)是一个用

于告诉接收方能够接受的数据量。

一般来说,发送方未确认的数据量不得超过cwnd和rwnd的最小值,也

就是

LastByteSent-LastByteAcked<=min(cwnd,rwnd)

由于每个数据包的往返时间是RTT,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论