计网第五章.运输层—TCP流量控制与可靠传输

以下来自湖科大计算机网络公开课笔记及个人所搜集资料

其实TCP的流量控制,可靠传输,拥塞控制,都是围绕滑动窗口机制来实现的,而UDP是没有滑动窗口的。

一、流量控制

目的:

TCP搞流量控制是希望发送方的发送速率别太快,否则接收方来不及接收。
— —发送方发出去的数据对方没接收,那么发送方就会重传,浪费流量

实现:

利用滑动窗口机制——三次握手的时候会协商好窗口信息

举例:

下面是A给B发送数据,B对A进行流量控制,发送rwnd(整个过程不详细记录了,注意看课程)

注意,本例中忽略拥塞控制,认为TCP发送方的发送窗口等于接收方的接收窗口。

实际是TCP发送方的发送窗口 = min(自身拥塞窗口,TCP接收方的接收窗口)
在这里插入图片描述
需要注意:

主机A的滑动窗口内的数据发送完后就不能再发送新数据,而是需要主机B对A发信息进行流控,里面包含主机B的接收窗口大小rwnd,然后主机A将自己的发送窗口大小也调整为这么大。上图中最后是0了,所以窗口没画出

涉及的英文字段:

seq: TCP报文段首部中的序号,取值1表示TCP报文段数据载荷的第一个字节的序号是1;上面一个报文发送 1~100号字节数据,即一次性发送100字节

DATA: 是报文的数据段;

大写ACK:首部中标志位的确认位,取值1,表示这是一个TCP确认报文段;(标志位是下图中保留字段右边那6个,每个都可以取值0、1,即只用1bit表示);

小写ack: 首部中的确认号字段(注意是第三行那个),取值201,表示序号201之前的数据已全部正确接收,现在希望收到序号201及其后续数据。正是因为它取值是字节序号,所以要用32bit来表示;

rwnd: 首部中的窗口字段,取值300,表示自己的接收窗口大小为300。

附上TCP报文首部:
在这里插入图片描述
在这里插入图片描述
IP首部是固定的,因为像目的地址、源地址、协议类型等字段是规定的;但是TCP首部包含的信息比较多,这些信息会根据具体情况而变化,因此TCP首部长度不固定
长度可变的“选项”部分,可以用于各种目的,比如最大分段大小MSS,窗口缩放、时间戳等等

死锁

上述过程的最后,是主机B给主机A发送的rwnd=0,那么主机A收到后就将发送窗口调控为0。然后主机A就等待主机B发送非0的窗口的通知。(接收和发送都会用0窗口)

此时,主机B的接收缓存又有了一些存储空间,将接收窗口调整为300,并发给主机A,然后等待主机A发来数据。但是该通告在路上丢失了。——这个还是不是普通TCP报文?还是仅有rwnd?——应该没有数据,只是报头

这个时候,主机A和主机B互相等待,形成死锁!!!
在这里插入图片描述

死锁的解决:

TCP为每一个连接设有一个持续计时器。

只要TCP连接的一方,收到对方的0窗口通知,就要启动持续计时器。若持续计时器超时,就要发送一个0窗口探测报文,仅携带1字节的数据,而对方在确认这个探测报文段时,给出自己现在的接收窗口值。如果接收窗口仍然是0,那么收到报文段的一方要重新启动持续计时器,如果接收窗口不是0,那么死锁的局面就可以被打破了。

本例中就是主机A收到B的0窗口通知,开始启动持续计时器,超时后就发1字节大小的探测报文。
在这里插入图片描述
TCP规定即使接收窗口为0,也必须接受零窗口探测报文段,确认报文段,以及携带有紧急数据的报文段。

如果零窗口报文段也丢失了呢?

零窗口探测报文段也有重传计时器,当重传计时器超时后,零窗口探测报文段会被重传。

二、超时重传时间的选择

超时重传时间RTO的值应该设置为略大于报文段往返时间RTT的值。
太小太大都有其缺点,超时重传时间过小:
在这里插入图片描述
超时重传时间过大:
在这里插入图片描述
而且,TCP下层是复杂的互联网环境,主机A所发送的报文段可能只经过一个高速率的局域网,也有可能经过多个低速率的网络,并且每个IP数据报的转发路由还可能不同。这就导致每次TCP的报文段的往返时间RTT不一致

如下,如果超时重传时间固定,而RTT变大,可能会导致不必要的重传:
在这里插入图片描述

解决方案

RTO略大于加权平均往返时间RTTs,其中RTTs和RTO计算分别如下:
在这里插入图片描述
在这里插入图片描述
但是这种算法中,万一RTT是错的呢?

尤其是在TCP报文丢失情况中,发送方会重传,接收方会返回一个TCP确认报文段,但是接收方分不出这是对上次报文段的确认还是对重传那次的报文段确认。因为重传是超时重传触发,不需要接收方发报文过来告知。

下图就是往返时间RTT偏大和偏小的情况:
在这里插入图片描述

Karn算法

针对上面的情况。在计算加权平均往返时间RTTS时,只要报文段重传了,就不采用其往返时间RTT样本,也就是不算出现重传之后不继续更新RTT了。

然而这要引起了新的问题,设想出现这样的情况,报文段的时延突然增大了很多,并且之后很长一段时间内都会保持这种时延,因此在原来得出的重传时间内,不会收到确认报文段,于是就重传报文段。根据Karn算法,不考虑重传的报文段的往返时间样本,这样超时重传时间就要无法更新,这会导致报文段反复被重传。

因此要对Karn算法进行修正,方法是报文段每重传一次,就把超时重传时间RTO增大一些,典型的做法是出现重传时,将新RTO的值取为旧RTO值的两倍。

实际中也不能一直超时重传,否则内核资源会一直得不到释放

像TCP的保活机制也是最多10次,就不再发送探测。TCP协议规定,如果超时重传超过一定次数,就给对方发一个RST,即连接重置报文,结束超时重传

reset是立即断开TCP连接,释放连接占用的系统资源(端口号,服务端的文件描述符fd)

三、可靠传输

TCP基于以字节为单位的滑动窗口来实现可靠传输。

可靠传输指的是该发送的字节都要让接收方收到。

示例图如下方,从31号字节到50号字节是待发送的。把50号字节称作前沿而不是31号,因为这个前沿指的是移动的前沿,而不是发送顺序的前后。所以向前移动也是下图的向右移动。

另外TCP标准**强烈不推荐前沿窗口回缩!!!**因为容易造成已经发送出去一些数据,却要求回缩到不能发送那些数据,这样造成错误。
在这里插入图片描述
如果要编程实现滑动窗口机制,怎么描述发送窗口的数量???

定义三个指针,如下图描述:
在这里插入图片描述
还要考虑发送窗口已发送完的字节序号和接收窗口已接收的字节序号不一致的情况,即所有已字节是否按需到达,有点类似之前数据链路层,可以回过去看看。
在这里插入图片描述
具体过程看源视频。

补充:

在这里插入图片描述
TCP这边按字节流,这只是TCP协议,实际上还是按以太网帧发送的,即按照报文发送,不是真的一个字节一个字节发给对面:

发送方的TCP‍‍把应用进程交付下来的数据块仅仅看作是一连串的无结构的字节流,‍‍TCP并不知道这些待传送的字节流的含义,仅将他们编号并存储在自己的发送缓存中。

TCP根据发送策略,从发送缓存中提取一定数量的字节,构建TCP报文段并发送‍‍。——这里就涉及到TCP分段了。

如果不分段,那么IP分片对于TCP来说是不清楚的,当某个TCP报文不完整到达对方,(比如项目里的服务请求,假设它这个字段很长,几千字节),那么TCP的重传机制就得重传整个报文,因为TCP并不知道IP把这个报文分成了几片,具体是哪一个IP片丢失。
如果TCP层分段了,那就可以知道哪一段丢失了,这样重传这一段即可。
TCP分段这块可以看看之前的博客:
TCP分段与IP分片的区别与联系

猜你喜欢

转载自blog.csdn.net/mrqiuwen/article/details/130113498