TCP解读(滑动窗口)

前端外刊评论 2018-01-28

基础知识解读

TCP是TCP/IP协议族中非常复杂的一个协议。它具有以下特点:

1:面向连接的运输层协议。在使用TCP协议之前,首先需要建立TCP连接。传送数据完毕后,必须释放已经建立的TCP连接。

2:一条TCP连接有两个端点,连接是点对点的。

3:提供可靠交付的服务。通过TCP连接传送的数据,不会出现差错不会丢失并且按序到达。

4:提供全双工通信。TCP允许通信双方的应用程序进程在任何时候都能发送数据。TCP连接的两端都设有缓存,分为发送缓存和接收缓存,用来临时存放双向通信的数据。发送时,应用程序把数据传给TCP的缓存后,就可以做自己的事情了。TCP会在合适的时候把数据发送出去。接收时,TCP把接收到的数据放入缓存,供上层的应用程序读取。

5:面向字节流。虽然应用程序和TCP的交互是一次一个数据块,但TCP把应用程序交下来的数据看成一串无结构的字节流。TCP对应用进程一次把多长的报文发送到TCP缓存中是不关心的。TCP根据对方给出的窗口值和当前网络的拥塞程度决定一个报文段包含多少字节。如果应用程序传到TCP缓存的数据块太长,TCP就会把它划分短些再传送。如果应用程序发来的数据太少时,TCP将会等待积累足够多的字节后再构成报文段发送出去。

TCP连接的端点叫做套接字。它是由IP和端口号构成。每一条TCP连接唯一的被通信两端的两个端点所确定。同一个IP地址可以有多个不同的TCP连接,而同一个端口号也可以出现在多个不同的TCP连接中。

TCP发送的报文段是交付给IP层传送的,但IP层只提供尽最大努力的交付。也就是说TCP下面的网络所提供的是不可靠的服务。可靠传输必须依靠TCP来实现。停止等待协议就是一种方式。

停止等待就是每发送完一个分组就停止发送,等待接收方的确认,在收到确认后再传送下一个分组。如果发送方在一段时间后仍然没有收到确认,就认为刚才发送的分组丢失了,因而重传前面发送过的分组,这被称为超时重传。要实现超时重传,就要在每发送完一个分组后设置一个超时计时器。如果在超时计时器到期之前收到了对方的确认,就撤销已设置的超时计时器。因此发送方在发送完一个分组之后,必须暂时保存已发送的分组的副本。只有在收到响应的确认后才能清除暂时保留的分组的副本。分组和确认分组都必须进行编号,这样才能知道哪一个发送过的数据已被确认,那些没有收到确认。超时计时器设置的重传时间应该比数据在分组传输的平均往返时间更长一些。超时重传时间的设定是非常复杂的,因为已发送的分组到底经过那些网络,以及这些网络会产生多大的延迟都是不确定的。

如果发送方发送了数据后,在超时时间内没有收到接收方的确认,它会重传数据。如果此时接受方再次接收到了此数据,它会将此数据丢弃,并向发送方发送确认。发送方没有收到确认,可能是因为接受方的确认出错或丢失。发送方还可能收到重复的确认,对待重复的确认只需要丢弃即可。上述可靠的传输协议被称为自动重传请求ARQ(AutomaticRepeatRequest)。采用停止等待协议可能会导致信道利用率非常低,为了提高传输效率,需要使用流水线传输。也就是说发送方可以连续发送多个分组,不必没发完一个分组就停下来等待对方的确认。这样可以使信道上一直有数据不间断的在传送。这被称为连续ARQ协议或滑动窗口协议。它比较复杂但却是TCP协议的精髓

滑动窗口

所谓滑动窗口就是说位于此窗口内的分组可以被连续的发送出去,而不需要等待对方的确认。发送方每收到一个确认,就会把发送窗口向前滑动一个分组的位置。假设此时1-5个分组位于发送窗口内,这5个分组就会被连续的发送出去。当发送方收到第一个分组的确认后,就会向后移动一个分组的位置,此时就可以发送第六个分组了。接收方一般都采用累积确认的方式。也就是说,接收方不必对收到的每个分组逐个发送确认,而是可以收到几个分组后,对按序到达的最后一个分组发送确认。这样就表示到这个分组为止的所有分组都被正确接收。如果此时发送方发送了前5个分组,而第三个分组丢失了,这是接收方只能对前两个分组发送确认。发送方不知道后面三个分组的下落。实际上仅仅第三个分组没有收到,但是发送方仍然会发送后三个分组。

下图显示了滑动窗口协议:

TCP解读(滑动窗口)

上面图中,将字节从1到11进行编号。接收方通告的窗口称为提供的窗口,它覆盖了从4到9字节的区域,表明接收方已经确认了3字节在内的数据,且通告窗口大小为6。发送方计算它的可用窗口,该窗口表明多少数据可以立即被发送,这就是常见的win选项

==========================================================================
当接收方确认数据后,这个滑动窗口不时的向右移动。窗口两个边沿的相对运动增加或减少了窗口的大小。我们使用三个术语来描述窗口左右边沿的运动:

TCP解读(滑动窗口)

(1)窗口合拢:窗口左边沿向右边沿靠近,这种现象发生在数据被发送和确认时
(2)窗口张开:窗口右边沿向右移动,运行发送更多的数据,这种现象发生在另一端的接受进程读取已经确认的数据,并释放了TCP的接受缓存时
(3)窗口收缩:窗口右边沿向左移动,这种方式不建议使用。
如果左边沿到达右边沿,则称为一个零窗口,此时发送方不能发送任何数据。
===========================================================================
下图显示了最上面例子的滑动窗口协议的动态性:

TCP解读(滑动窗口)

1)发送方不必发送一个全窗口大小的数据;

(2)来自接收方的一个报文段确认数据把窗口向右滑动。这是因为窗口的大小是相对于确认序号的;
(3)报文7和报文8变化,可以看出窗口的大小可以减小,但是窗口的右边沿却不能向左移动;
(4)接收方在发送一个ACK前不必等待窗口被填满。
==================================================================
窗口大小
由接收方提供的窗口大小通常可以由接受进程控制,这将影响TCP的性能。插口API运行进程设置发送和接收缓存的大小。接收缓存的大小是该连接上所能够告知的最大窗口大小。
*************************************************************************************************
PUSH标志
发送方使用PUSH通知接收方将所有收到的数据全部提交给接收进程。这里的数据包括和PUSH一起传送的数据,以及接收方TCP已经为接收进程收到的其它数据。
在最初的TCP规范中,一般假定编程接口允许发送进程告诉它的TCP何时设置PUSH标志。
(1)通过允许客户应用程序通知其TCP设置PUSH标志,客户进程通知TCP在向服务器发送一个报文段时不要因等待额外数据而使已提交数据在缓存中滞留;
(2)类似地,当服务器的TCP接收到一个设置了PUSH标志的报文段时,它需要立即将这些数据递交给服务器进程,而不能等待判断是否还会额外的数据到达。
如果待发送的数据将清空发送缓存,则大多数的源于伯克利的实现能够自动设置PUSH标志。这意味着我们能够观察到每个应用程序写的数据均被设置了PUSH标志,因为数据在写的时候立即被发送。

TCP首部

TCP是面向字节流的,但是TCP传送的数据却是报文段。一个TCP报文段分为首部和数据两部分。只有真正弄清TCP的首部各字段的作用才能掌握TCP的原理。

TCP的前20个字节是固定的。后面的40字节是根据需要增加的。因此TCP首部的最小长度时20。

1:源端口和目的端口:各占两个字节。

2:序号:四个字节。共2的32次方个序号。TCP连接中传送的字节流中的每一个字节都按顺序编号。此处的序号字段指的是本报文段所发送的数据第一个字节的序号。

3:确认号:4个字节。表示期望收到对方下一个报文段的第一个数据字节的序号。如确认号是N,则表明序号N-1之前的数据都正确收到。确认号也是4个字节,可以对4GB数据进行编号。

4:数据偏移,4位。它指出TCP报文段的数据起始处距离TCP报文段起始处有多远。这个字段实际上指出了TCP的首部。由于首部中有长度不确定的选项字段,因此此数据偏移是必要的。数据偏移只有4位,但是它的一个单位代表4字节。因此数据偏移的最大值是60(15*4)。即TCP首部的最大长度。

5:保留6位。保留为以后使用。都是0.

6:紧急URG当此处为1时,表明紧急指针字段有效。它告诉系统此报文段有紧急数据,需要尽快传送。系统会把紧急数据插入TCP缓存的最前面。它和紧急指针字段配合使用。

7:确认ACK:当ACK=1时,确认号字段才有效。当ACK=0时确认号无效。当连接建立前ACK=0,建立之后ACK就一直是1了。

8:推送PSH。当PSH=1时,系统会立即将此报文段发送出去,而不再等待整个缓存都被填满后才向上交付。

9:复位RST。当其为1,时,表明TCP出现严重错误,必须释放连接然后再重新建立连。

10:同步SYN:在连接建立时用来同步序号。当其为1而ACK=0时,表明这是一个(同步)连接请求报文段。当对方同意后,应在响应报文段中使用SYN=1,ACK=1。因此SYN=1,要么表示连接请求要么表示连接接受报文。

11:终止FIN:用来释放连接。当其为1时,表明此报文段的发送方的数据已经发送完毕,要求释放连接。

12:窗口:2字节。窗口指发送方的接收窗口。它告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量。之所以有此限制是因为接收方的数据缓存空间是有限的。它指出现在允许对方发送数据量。由于接收缓存不断变化,因此窗口值也不断变化。

13:检验和:2字节。检验和检验的是首部和数据这两部分。在计算时还应加上12字节的伪首部。

14:紧急指针:2字节,此字段只在紧急URG=1时才有意义。它指出本报文段中紧急数据的字节数。由于紧急数据放在了缓冲区最前方,紧急指针指出的是紧急数据的末尾在报文段的位置。当所有的紧急数据都处理完后,TCP就告诉应用程序恢复正常操作。

15:选项:长度可变,最长可达40字节。当没有选项时,首部长度时20.

MSS是选项的一种。它被称为最大报文段长度,是每个TCP报文段中数据字段的最大长度。它加上TCP首部才是整个TCP报文段。再加上20字节的IP首部才能组装成一个IP数据报。当MSS非常小时,网络的利用率就低。如果发送只含一个字节的数据时,在IP层传输至少需要40字节的开销(IP头20字节,TCP头至少20)。到链路层还需要开销。如果MSS非常大,在IP层传输时就可能要分片,到终点后再将各个分片组装成原来的TCP报文段,这也会使开销增大。因此,MSS可以尽量大,只要在IP层传输时不分片就行了。MSS的默认长度时536。

窗口扩大选项是为了扩大窗口,窗口字段长度是16位,因此最大的窗口大小是64字节。窗口扩大选项占3个字节。每一个字节表示移位值。新的窗口值等于原来的16+窗口扩大选项的值。这相当于把窗口值向左移动移位值位。

时间戳选项占10字节,最主要的两个地段是:时间戳值和时间戳回送回答字段。

时间戳选项具有以下两个功能

1:计算往返时间。

2:用于处理TCP序号超过2的32次方的情况。这又被称为防止序号绕回。在报文段中加入时间戳就可以区分新的报文段和迟到很久的报文段。

socket的两端分别有两个窗口,发送窗口和接收窗口。滑动窗口的单位是字节,假设A收到了B的确认报文段,其中窗口时20,而确认号是31,这表明B期望接受的下一个序号是31,到序号30为止的数据已经收到了。根据这两个数据,A就构造自己的发送窗口。它的起始值为31,而末尾值为50。发送窗口表示在没有收到B的确认前,A可以连续把窗口内的数据都发送出去。

凡是已经发送过得数据,在未收到确认之前都必须暂时保留,以便在在超时重传。发送窗口内的序号表示允许发送的序号。

发送窗口与缓存的关系。

发送窗口存储应用程序将要发送的数据,以及发送但却为收到确认的数据。发送窗口只是发送缓存的一部分,已经被确认过的数据应当从发送缓存中删除。因此发送缓存和发送窗口的后沿是重合的。

接收缓存用来暂时存放按需到达的,但还未被应用程序读取的数据以及未按序到达的数据。如果收到的分组有差错,就要丢弃。如果接收应用程序来不及读取,接收缓存就会被填满,就会减少接受窗口,直到减为0。反之就可以增大。

虽然发送方的发送窗口是根据接收方方接收窗口设置但是,但同一时刻,发送窗口并不一定与接收窗口相同。这是因为通过网络传送窗口值需要经历一定的延迟。

TCP要求接收方必须有累计确认的功能,这样可以减小传输开销。接收方可以在合适的时候发送确认,也可以在自己有数据发送时把确认信息捎上。但应该注意的是接收方不应过分推迟发送确认,否则会导致发送方不必要的重传,这反而会浪费网络资源。

TCP利用滑动窗口来实现流量控制。所谓流量控制就是让发送方的发送速率不要太快,要让接收方来得及接受。在连接建立时,发送方告诉接收方我的接受窗口是x,接收方收到后会设置自己的发送窗口。发送方的发送窗口不能超过接收方给出的接收窗口的数值。TCP窗口的单位是字节,而不是报文段。在每次发送数据是报文段内会将此时接受窗口告诉发送者。发送者会根据收到的报文段接收窗口的值调整自己的发送窗口。当接收方接收缓存满时就发送给发送方零窗口,告诉发送方停止发送。假设过一段时间接收方调整接收窗口为100,而此报文段在传送过程中丢失,这就导致发送方等待接收方的非零窗口通知,而接收方在等待发送方的数据。这样就导致了死锁。为了防止这种情况,TCP为每个连接设置一个持续计时器。TCP连接的一方收到零窗口通知后,就启动计时器,设置的时间到期后它会发送一个探测报文段。如果此时返回的仍然是零窗口,则重新设定计时器。如果窗口不是零,那么死锁的僵局就可以被打破了。

相关推荐