您的位置:首页 > 理论基础 > 计算机网络

tcp/ip ---------- 网际协议之tcp

2015-06-01 20:52 686 查看
可靠交付服务的特征:

1、 面向数据流

2、 虚电路连接(打电话类似)

3、 有缓冲的传输

4、 无结构的数据流

5、 全双工连接

提供可靠性

即要求接收方收到数据之后向源站回送确认ACK报文

发送发对发出的每个分组都保存一份记录,在发送下一个分组之前等待确认信息

发送方还在发出分组时启动一个定时器,并在定时器超时而确认信息还没到的情况下重发刚才的分组。

滑动窗口

为了获得可靠性,发送方送出一个分组后,等待相应的确认信息而不发送下一个分组。然而这样导致的结果可以想象,很大一段时间的资源被浪费了!

滑动窗口更好的利用了网络带宽,因为他允许发送方在等待确认之前可以发送多个分组。

如果一个分组被发送后没有收到确认,我们称这个分组是未被确认的。从理论上讲,任意时刻未被确认的分组数取决于窗口大小,并被限定在一个固定的小数目内

如上图,发送方可以在未收到确认信息之前发送8个分组

从理论上来讲,滑动窗口协议要记录哪些分组已被确认,并为每个未确认的分组设定定时器。如果某个分组丢失,对应的定时器超时之后发送方就会重新传输这个分组

一旦受到确认,发送方就会滑动其窗口,把所有已确认的分组移动到窗口之外

所以,窗口把所有分组划分为3个部分:

1、 窗口左边是已经成功传输、接收和确认的

2、 窗口内的分组是已经发送了的(未收到确认的)

3、 窗口右边分组时还没发送的

TCP数据流和序号

TCP即是用了滑动窗口的概念

但因为TCP是数据流形式的,所以会为八位或者一个字节编序号,而为了便于传输又把这些序列划分为若干个段。

所以我们知道了TCP是以字节来传输数据而不是分组。

发送方为每个连接保留了3个指针。这些指针定义了一个滑动窗口。如下:

位于滑动窗口左边的第一个指针把已经发送并得到确认的字节与尚未得到确认的字节区分开来。

第三个指针标出了窗口的右边界,指出序列中在未得到确认的情况下可以发送的最高字节的序号

第二个指针位于窗口的内部,它划分出已经发送的字节和尚未发送却可以发送的字节之间的界限。

我们知道了发送方的TCP窗口如何滑动,而接收方必须保留一个类似的窗口把这些字节拼到一起。又因为TCP是全双工的,任何时候都可能有数据在一个或两个方向传输。因此,在连接两端的TCP软件为每个连接方向各保留了两个窗口(共四个),其中一个在发送数据时滑动,另一个在接受数据时滑动

可变窗口大小与流量控制

TCP允许随时改变窗口的大小。

每个确认中,除了指出已经收到的字节,还包括一个窗口通告来说明接受方还能再接受多少字节的数据。根据这个窗口通告,发送方需要适当的改变发送窗口的大小。

这样一来,滑动窗口不仅提供了可靠传输,还提供了流量控制

在某些极端情况下,接收方接收缓存满了,因此发送窗口为0的通告来停止数据传输,此时会有两种例外的传输情况

1、 一种是发送方传输的报文段中紧急位置一,使得接收方知道是紧急数据

2、 为了避免窗口大小到0之后非0窗口通告丢失造成死锁,发送方定时的对大小为0的窗口发出试探性报文段

最大报文段长度选项

这是TCP的一个选项

所有的报文段可能是以不同的长度在一个连接上传输的,因此一个连接的两端必须协商一个最大段长度值。TCP软件使用一个选项来指定本端所能接收的报文段长度的最大值MSS

如果连接的两段不在同一网段上,它们就会把连接所经过的路径上最小的MTU作为MSS ,也可以把536作为最大报文段长度(IP数据报默认576,减去TCP和IP首部)

但是,在实际的网络上,选择合适的最大报文段长度是很困难的,过大或者过小都会影响网络性能,因为太大可能会在半路被分片,太小利用率太低

窗口扩大因子选项 wscale

在TCP首部中,通告窗口大小是用16位表示的,最大只能为65535字节,但实际上TCP允许的窗口大小远不止这么点。于是有了窗口的扩大因子来解决这个问题。

假设通告窗口大小为N,扩大因子是N,那么实际接收通告窗口大小为 N*2^M

确认与重传

TCP的确认方法为累计确认,因为他报告了已经积累了多少个字节的数据流。这种确认方式优缺点都有。

优点是这种确认容易产生,若确认信息丢失但并不一定迫使对方重传

缺点在于发送方不能知道所有成功传输的报文段的确认信息,只知道已收到数据流中某个位置的信息。

缺点之所以是缺点,是因为如果发送方要发送从101开始的5000个字节的窗口,发送方使用5个报文段发完了这么多字节,如果第一个报文段不幸丢失而其他报文段正确到达,那么每个报文段到达时接收方发回的确认却都是指向它希望收到的第一个报文段,即101,无法告知发送方大部分数据其实已正确接收了。

然而这时候发送方出现了超时,它必须做个选择:全部重传或是只重传期盼的那个报文段。全部重传明显低效;如果选择只重传一个,那么问题又来了,发送方并不知道接收端到底接收到哪些数据了,这时候只有等待这第一个报文段的确认再做判断,如果确认是5101,说明不要再传了,可这就违背了我们滑动窗口的协议!成了简单的效率低下的发送-确认-发送协议了!

所以,这里存在的问题,下面会得到答案。

超时与重传

挺复杂的。。。

TCP希望目的站成功的从数据流中接收新的数据后能够回送确认信息。每发送一个报文段,TCP就设定一个定时器并等待确认信息。如果超时且未收到确认,TCP重传

在互联网中,在一对机器之间传输的报文段可能只经过一个时延很低的网络,也可能要经过多个路由器,通过多个中间网络。因此不可能预知确认信息何时会回到发送方

此外,每个路由器产生的时延取决于通信量,所以报文段到达目的站和确认回到源站的时间总和可能会发生显著的变化。

TCP使用自适应重传算法来适应互联网时延的变化,该算法的要点是:TCP监视每个连接的性能,由此推算出合适的定时时限。当连接性能变化时,TCP随即修改定时时限。(即TCP的等待确认的定时器会随时延的变化而变化)

TCP记录样本的往返时间,每当得到新的样本的往返时间(NEW_ROUND_TRIP_SAMPLE),TCP就修改这个样本的平均往返时间。通常平均往返时间为:

RTT = (a * OLD_RTT) + (1 – a)* NEW_ROUND_TRIP_SAMPLE;

可见,变量a越接近0,变化越快。

发送分组时,TCP计算出定时时限,如下计算:

Timeout = B * RTT;

选择合适的B很难,一方面为了尽可能快的检测出分组的丢失,定时时限要尽可能的接近当前往返时间(即B接近1),这样迅速检测出分组丢失可以提供网络吞吐量,因为TCP在重传之前不需要长时间的等待;然而如果B=1,那TCP显得太急切,任何微小的时延都会导致不必要的重传,浪费网络带宽

最初规范B为2,下面我们会给出更好的办法。

往返时间样本的精确测量

因为累计确认方式的存在,它是对接收到的数据而不是对携带这些数据的特定数据报进行确认。

TCP此时发送一个报文段,超时了,又发送一个报文段,此时确认来了,因为发送的两个报文段包含了相同的数据,发送方就无法确认确认信息到底是针对哪个数据报的,因此TCP的确认具备了二义性。

如果TCP认为确认信息是针对一开始的那一次发送的,而实际情况是第n次重传的确认,那么RTT将会不断变大

而如果确认信息是针对最近一次发送的,那么可能会因为与实际情况不符而造成RTT变得越来越小。观察那些把确认信息设定为属于最近一次传输TCP软件,会发现其RTT值会稳定在略小于正确时间值的一半以上(这样,即使没丢失,TCP也会把每个报文段传输两次)

Karn算法与定时器补偿

现在问题摆在我们面前,如果无法用原先的传输或最近的重传来计算准确的往返时间,那么TCP该怎么办?

解决的办法是:TCP不应更改重传报文段的往返时间估计值。

这种方法避免了确认二义性带来的问题,只对没有二义性的确认(即对只发送一次的报文段的到达的确认)的往返时间进行调整

然而,若只是单纯的这样忽略二义性的确认,某一刻突然某些原因延时增大,TCP根据现有的往返估计值设定的超时时限到期,(可以想象,此超时时限比当前延时小的多)从而造成重传。如果TCP忽略了重传对往返时间的影响,它就不会据此修改往返时间估计值,使得反复重传的循环继续下去。

为了解决上述问题,Karn算法要求发送方使用定时器补偿策略来把超市重传的影响估算在内:

New_Timeout = y * Timeout; (y 一般为2)

总的来说,该算法就是忽略二义性并给予补偿。

一般而言,Karn算法并不使用当前的往返时间估计值来计算定时器的时限。它使用往返时间估计值来计算初始时限,再在每次重传时对时限进行补偿,直达成功的传送一个报文段为止。在发送后序的报文段时,保持时限不变,最后在收到指出某报文段无需重传的确认后,TCP重新计算往返时间估计并设定时限

对拥塞的响应

拥塞是由于在一个或若干个交换网点(如路由器)的数据包负载过重而出现的严重的时延。发生拥塞时时延增加,而路由器把大量数据报放入队列中,直到能够处理他们。由于每个路由器存储能力是有限的,数据容量达到饱和后,路由器开始丢弃报文。

对于正在通信的端点来说,其通常不知道因何或在何处发生拥塞等细节,对于端点来说,拥塞表现为延时增加。

根据之前所学,我们知道延时增加总是导致重传。然而,这种情况重传只会导致情况更加严重,最终导致拥塞崩溃!

为了避免这种情况,于是出现了慢启动和拥塞避免

这里就不讲了。

糊涂窗口综合症与短分组

收发两端的应用程序以不同的速率工作时,软件性能会出现严重的问题,

这里,我们来考虑接收方应用程序每次仅读取一个字节的情况。

建立连接后,接收方TCP软件申请n字节的缓存空间,在建立连接时告知窗口大小。如果发送方快速产生了数据并传输了过来,很快接收方缓存区就被填满了。这时候接收方发送接收窗口已饱和的确认信息给发送方,发送方就不再继续发送数据过来。

当接收方从饱和的缓冲区读取1个字节数据后,就有了1个字节的可用缓冲区。此时,接收方就会发送1个确认给发送方,通告了已有的1字节大小的窗口。

发送方得知可用空间后,就发生包含1个字节的报文段过去。

然而我们知道,发送这种短的报文段肯定会浪费网络宽带。

接收方可能会导致产生短的报文段,发送方也会产生这种问题。

1、 发送程序每次产生1字节数据,且TCP的实现是只要有数据就发送,此时TCP也会产生这种短报文

2、 应用程序生成的固定大小为B字节的数据,而TCP一次从缓冲区中取出的数据字节数为M字节,此时若M<B,那缓冲区剩下的少量字节也会成为短报文

上述为题即为糊涂窗口综合症

避免糊涂窗口综合症

现行的TCP使用启发式的方法避免糊涂窗口综合症

1、 发送方避免发送短报文

2、 接收方避免送出小窗口通告

当然,因为TCP是全双工的。双方都可能成为发送方或接收方

措施一:接收方糊涂窗口的避免

通常接收方为当前可用的窗口值维护一个内部记录,并在窗口大小显著增加之前推迟发送增加窗口的通告

此处的“显著”,TCP认为窗口大小至少为缓冲区空间的一半或者最长报文中所含字节数目时才称为“显著”

所以,概括来说,接收端避免糊涂窗口综合症的方式是:通告零窗口后,要等到缓冲区可用空间大小达到总空间的一半或曾有的最大长度之后才发送更新的窗口通告

措施二:推迟确认

接收方实现避免糊涂窗口综合症有两种方式:

1、 如刚才所讲,到达一定限度后才发窗口通告

2、 在窗口大小不足以避免综合症时,推迟发送确认(TCP标识推荐)

推迟确认优点是推迟的确认能降低通信量且提高吞吐量。

1、 在确认期间接受到新数据可以一起确认了

2、 如果接收方正好要响应,正好就把确认捎带在数据报文段中

3、 这段时间接收方读取缓冲区数据,窗口增大通告可随确认一起发送

(在立即确认机制的TCP实现中,通常在立即发送确认后,接收方读取数据,然后再发一个窗口通告过去)

主要缺点是当接收方的确认延时太大时,发送方会进行报文段的重传

此外,TCP使用确认的时间来计算往返时间,推迟确认会造成估计值混乱并增大重传时间

为了避免潜在问题,TCP标准规定了推迟确认的时间限度,规定最多推迟500毫秒

此外,为了使TCP尽量准确更新往返时间,TCP标准推荐接收方至少每隔一个报文段使用正常的方式对报文段进行确认

措施三、发送方糊涂窗口的避免

目的是防止发送短的报文段,而应用程序是可以被允许按很小的块来生成数据的,因此应用程序是被允许多次调用写操作的,而TCP则收集起来形成较长的报文段来传输

所以发送方TCP在发送报文段之前必须延迟,以积聚合理的数据量

那TCP应该等待多久呢?等太久会导致延时过长,过短则可能无法避免报文段过短。

对于用途广泛的TCP来说,在TCP上传输的字符可能来自键盘,可能来自文件,一个固定的时延无法适应所有情况

与慢启动与拥塞避免算法一样,TCP避免发送短报文的技术也有自适应能力,其时延根据互联网的当前性能决定。

使用的策略是Nagle算法:

在一个连接上已经传输的数据还未被确认的情况下,发送方的应用程序又生成了后续数据,并照常将数据送到输出缓冲区中。但这时并不发送后序报文段,而是等到前一个报文段的确认到达之后再把缓冲区中的数据发送出去
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: