《一个陌生女人的来信》迷人的TCP协议

704 阅读17分钟

前言

最近梳理网络知识。这是网络知识《一个陌生女人来信》的第三篇。为什么叫这个名字,因为前面的文章都是这个名字,借它网络文章整理一起.

为什么前面的文章要叫这个名字,类似递归,去问前前面的文章吧 😂

在第一篇说的是TCP建立连接过程和网路中的一些基础知识,比如TCP报文格式不清楚的掘友强烈建议看完第一篇再看第三篇,文章末尾有第一篇的链接👀

这一篇文章你会深入理解滑动窗口,拥塞控制,拥塞避免等TCP相关知识和UDP的一些使用场景😃

看完一半您能知道滑动窗口是个什么东西以及到底是怎么滑动的,看完全部还可以知道拥塞控制,流量控制的过程以及UDP使用场景~~~

第一节:TCP可靠传输的实现

为什么说TCP是可靠的协议呢? 其表现在五个方面,TCP保证了传输的顺序,丢包了会重新发送,双发握手挥手保证有始有终,服务器接收能力进行流量控制,根据网络状况的拥塞控制

1.如何保证顺序(乱序,丢包)

为了保证顺序,每一个都有一个序列号,可以理解为ID号。建立连接的时候会规定起始ID,然后按顺序一个个发送。为了不丢包,对于发送的包也会进行应答。

当然这个应该不是一个个应答,而是累计应答(确认)。应答的是之前的某个ID,表示这个ID之前的包(多个)我都收到了。

接着引入TCP中的滑动窗口,发送端滑动窗口大家应该耳熟能详,分为四部分,已发送已确认,已发送未确认,未发送可以发送,未发送不能发送四个部分。接收端的滑动窗口分为三部分,已接收并且交付给主机允许接受(未接收可以接收+已接收未交付)未接收也不能接收三个部分

一些博客里也没有演示滑动窗口的过程可能会导致一些没有网络基础的掘友无法真正理解,下面玲珑就演示一下发送的过程吧。用A表示发送端,B表示接收端。😎

  1. 初始:

    假如A收到了B发来的确认报文段,规定窗口大小是10字节,注意TCP的窗口是以字节为的单位的。B发送的确认号=31(表示希望收到的下一个序列号),说明31之前的数据B都收到了。根据确认号窗口字节大小这两个参数A构造出自己的滑动窗口

  • A在没有收到B的确认之前,可以把发送窗口的数据都发送过去,也就是31-40字节的数据。凡是发过去的数据要暂时保留,以便超时重传的时候使用。
  • 发送窗口后面的表示已发送已确认的可以不用再保留,未发送还没有发送的要保留。
  1. A发送数据给B:
假如A发送了前面四个数据给B,但是还无法得知B是否收到。A的发送窗口大小还没有改变。

  • A的发送窗口由已发送未确认和可发送未发送两部分组成,可发送未发送的就是有效窗口(可用窗口)。
  1. B接收的情况:
  • 这里B接收窗口也是10字节。
  • 这里B接收到了32,33这两个序列号的数据,31的数据可能丢失也可能滞留在网络中。那么B发出的确认号任然是31(下一次期望收到的序列号)

敲重点!!!B发出的确认号任然是31(下一次期望收到的序列号),32,33的数据暂存。

  • B发出ack=31的确认号,A收到B的确认

    • A收到B的确认后再发31的数据(图略)
  • B收到31的数据发出ack=34的确认号

    • B将31,32,33的数据交付给主机,然后B就会删除这些已确认和交付给主机的数据同时给A发确认希望下一次的序列号是34。
    • B的接收窗口大小不变,向前滑动3个数据。
    • A收到B的确认后,31,32,33这三个数据是已发送已确认状态,不属于发送窗口,发送窗口也向前移三个序列,此时可用窗口变大了3个数据(由35->43)。

  • B收到序列号34
    • B收到34序列号的数据后将他交付到主机,接收窗口后移一个序列。发送ack=35的确认号。
    • 此时A收到后发送窗口大小变成35-44,B的接收窗口变成35-44、
  • A一口气发完了发送窗口所有数据,B也确认ack=45
    • A发完可用窗口35-44的所有数据后,B进行确认,希望下一个序列号是45
    • 但是A没有收到B的确认号(丢包)
    • 为了保证可靠传输A只能认为B没有收到,所以A经过一段时间(超时计时器控制)后,重新发送35-44的数据。直到A收到B的ack=45确认号,如果确认号落在发送窗口内,A的发送窗口就可以继续向前滑动,并发送新数据。

细心的小可爱肯定看出来上面说的不就是乱序丢包两个问题嘛,没错,那机智的你知道重发机制吗?😎

出现连续和丢包后接收窗口也没有办法发送ACK,发送窗口就要一直等待确认。没有收到确认于是发送窗口会进行重发序列号。

重发序列号就要重发机制。

2.重发机制

重发的机制有两个,一个是超时重试,一个是超时重试上的改进选择确认

2.1.超时重试

超时重试:发送端采用自适应算法,接收端快速重传机制触发发送端快速重传。

对于发送没确认的包设置一个定时器,超过一个设定的时间后就会重发,也是我们上面刚刚说的那个方法。这个时间必须大于往返的RTT,时间过长访问变慢,时间过短则引起一些不必要的重传。

TCP通过采用RTT进行加权平均值(加权使结果变得更加平滑),算出一个值。这个值根据网络状况不断变化,因而也叫自适应重传算法。当超时重传的次数大于1,就会将下一次超时时间间隔设置为之前的两倍。如果两次超时就说明网络环境差,不宜反复发送。

自适应重传算法式发送端根据发送没有确认的包设置定时器的一种超时重试进制,还有一种快速重传机制表现在接收方。接收方收到一个序列号大于下一个期望收到的序列号的时候,会检测到数据中的一个间隔,于是就会发送重复的ACK,当接收方收到3个重复的ACK后就会在定时器过期前重传丢失的报文。

不用等待那个发送方的计数器计时结束后再发送,接收方收到3个冗余ACK立即重发。

2.2.选择确认SACK

选择确认是便于处理乱序问题,接收到的报文没有查错,只是没有按序到达,可以只重传没到达的包而不用重传已经正确到达的包。

使用选择确认SACK,就要在TCP的首部中选项加上:允许SACK的选项。例如接收端发送ACK30,ACK32,ACK33.那么发送发就知道31这个序列号丢了。

第二节:TCP流量控制

1. 接收端对发送窗口的控制

流量控制是接收方控制发送方发送窗口大小,你发送发发送的不要太快,要让我接收方来的及接收。也不要发的太慢让我等着。

出现的原因是接收方缓存的数据处理的速度的快慢。极端的情况是接收端的应用如果一直不处理接收端缓存的数据,就会使接收窗口变小,接收方通过确认信息修改发送发窗口的大小。

下面看图来演示一下。红色箭头表示流量控制

B对A的发送窗口进行了两次控制,第一次由最开始的400变为200,因为接收端收到1-200字节的数据一直在缓存中没有交付给主机,因此可以接收还没接收的数据量是200字节,他告诉A我的接收窗口是200字节。

B对A的发送窗口进行的第二次控制是由200字节变为0字节,还是因为接收端滑动窗口缓存的数据没有被使用,一直呆在缓存中。

2. 流量控制的问题

流量控制虽好,但是出现一种情况。如果B的缓存中可以接收新的数据了,于是通过ACK报文将rwnd的值传递过去的时候丢失在网络中没有到达发送端。

接收端却一直在等发送端发送数据过来,发送端在等接收端的rwnd。然后双方一直等待,处于死锁。

为了解决这个问题。TCP为每一个连接设置了有一个持续计时器。如果接收端收到了0窗口通知就会启动持续计时器.持续计时器到期就会发送一个0窗口的探测报文段(1字节数据),接收端就会回应rwnd的值,如果还是0,接收端就会重置持续计时器。如果不是0就可以接着发数据。

第三节:TCP拥塞控制

什么是拥塞

什么是拥塞,可以想象堵车,车很多但是路就只有那么宽,所以当所需的车多了需要的道路也变宽了,但是路只有那么宽。所以出现了拥塞现象,也就是对道路的宽度需求大于所提供的宽度。如何减少拥塞呢?当然是堵车就是不去添乱,等车少了再去

产生拥塞的原因:对资源的请求>可用资源。这里的资源就是网络中的带宽(链路容量),交换结点中的缓存和处理机等资源。

拿带宽来说,资源不够就要减小可发送的窗口数量,如果带宽少了窗口越来越大就会越来越堵,堵死了。。。

拿交换结点的缓存来说。如果发送方发送的速率变大,单位时间内会有更多的数据包到中间设备,中间设备单位时间处理的数据是有限的,暂时不能处理的就会放到缓存中产生一定的时延,时延到达一定程度就会超时重传。

发送方的拥塞窗口根据网络是否出现拥塞来增大或减小拥塞窗口。

下面引入拥塞窗口和慢启动阈值这两个概念。然后来看看经典的拥塞避免图来分析TCP拥塞控制的过程。其实这张图很好理解的,把它看作普通的函数图像就好了🐱‍🚀。

  • 拥塞窗口:cwnd
  • 慢启动阈(yu四声:意为门限也)值:ssthresh
    我们一个一个阶段来分析~

1. 算法一:慢开始阶段

发送端发送SYN,刚开始不知道网络环境到底怎么样,所以慢慢试探由小到大逐渐增大发送窗口。发送端发给接收端的数据最开始假如是1,那么接收端收到后发送确认ACK给发送端,发送端的拥塞窗口就加1,每收到一个来自接收端的ACK拥塞窗口都会加1.

也就是会扩大一倍,这很好理解。当第一次发送拥塞窗口是1,收到ACK后发送窗口就变成2。如果这两个的ACK都收到后拥塞窗口就变成了4。第三次发送四个序列号数据如果ACK都收到后拥塞窗口大小为8....直到达到一个上限,因为拥塞窗口不可能一直无限扩大两倍呀。

2. 算法二:拥塞避免阶段

第一阶段我们说的上限就是ssthresh,慢启动阈值。达到慢启动阈值后滑动窗口不会增加那么快,假如16是阈值,下一次发送16个数据,每收到一个数据的ACK拥塞窗口就会增加1/16.如果收到16个确认的ACK才窗口才会增大1。

3. 超时回到慢开始

当拥塞窗口一直增大到图中24的时候出现超时,但是实际上网络中没有拥塞,由发送方迟迟收不到确认就会产生超时,误认为出现了拥塞。导致发送方错误的启动了慢开始,将拥塞窗口的值又设置为1.那么传输的速率会降低很多,这个也不难理解。

并且还会调整这次慢开始的阈值为cwnd/2=12.

虽然这种版本不用了,但是原理还是需要知道滴

4. 快恢复阶段

快恢复阶段是为了解决超时后回到慢开始效率降低的问题的一种新的算法

还记得我们在前面重发机制中的快速重传嘛,发送发收到连续的3个ACK,就知道接收方没有接受到报文段。

此时不会开始慢开始,而是开始的cwnd=cwnd/2,将阈值为cwnd的值。也就是cwnd=ssthresh。

然后进行拥塞避免算法,直线增长。

注意:也有将开始的cwnd=ssthresh+3.因为收到了3个确认ACK就说明这三个分组不再网络中,而是在接收方的缓存中,因此网络中减少了三个数据。

5. BBR拥塞算法

为什么会有新的BBR拥塞算法? 主要是TCP传统的拥塞算法中存在以下两个问题:

  1. 拥塞避免的时候无法区分是拥塞还是错误引起的丢包。可用资源还有但是也出现拥塞可能是网络错误了
  2. 缓冲区膨胀,这点上面都有说,就不过多解释。

BBR是如何解决的呢? BBR拥塞算法试图找到一个平衡点,通过不断加快发送速度填充中间设备缓存,但是不会填的太满,找到一个满足高带宽和低时延的平衡点。

拥塞控制和流量控制总结

上面说了拥塞控制和流量控制,我们可以发现:

  1. 拥塞控制是发送方根据网络环境来决定拥塞窗口的大小。
  2. 流量控制是接受方根据自己窗口中缓存中的数据来决定发送方发送窗口的大小。
  3. 发送发窗口的大小或者说发送窗口的上限值=min(cwnd,rwnd),谁小谁就控制了发送方发送数据的速率。

第四节:TCP快速打开TFO

相信你对TCP有了足够的认识了,那么TCP每次都要握手后建立连接才能够传输数据,是不是很麻烦,有没有在建立好连接之前就进行数据的传输呢?

TFO就是对于TCP的一种优化,在建立连接的时候就可传输数据,也就是在第三次握手最后的ACK包收到之前就可以传输数据,降低了一个往返时延。在传输开始就降低了时延。

TFO快速打开的原理分为首轮三次握手和后面的三次握手,神三元的TCP系列的TCP快速打开原理有详细说明。

主要是第一次三次握手的时候接受方给发送方一个cookie,这个cookie在TCP报文的fast-open选项中,接受方收到了继续完成当前的三次握手。

后面接收方和发送方进行三次握手的时候,发送方就会将cooike同SYN报文同HTTP请求一起发给接受方,接收方验证cookie如果合法返回ACK+ack+HTTP响应。如果不合法就丢弃。

第三次握手发送方接着返回ACK。

第五节:UDP的应用场景

说了这么多TCP好像TCP就是比UDP好,其实不然,很多场景有UDP的影子。下面的内容都来自极客时间的趣谈网络专栏。

UDP和TCP最大的区别就是面向无连接。这个连接并不是建立一条连接的通路,而是双发建立的一定数据结构维护双方的通信的状态用这样的数据结构保证面向连接的特性,维护连接的状态。

  • UDP继承了IP包的特性,不保证丢失,不保证按序到达;TCP提供可靠的交付
  • UDP继承IP包的特性,基于数据包一个个发一个个接收,TCP基于字节流
  • UDP不会拥塞控制,让我发就发不管当时的网络状况,TCP可以拥塞控制
  • UDP是无状态服务,TCP是有状态服务的

总的来说,UDP传输数据方式简单,相信网络世界是美好的认为数据能够很容易到达。UDP不是一对一的通信。甚至同时可以给对个进程传输数据。UDP不管网络情况自己发自己的。

使用场景

  1. 需要资源少,网络情况较好丢包不敏感。DHCP就是基于UDP的协议
  2. 不用一对一沟通,是可以广播或多播的应用。DHCP是广播,D类地址组播地址,云网络中的VXLAN要用到组播,也是基于UDP的
  3. 可以容忍少数丢包,即使是网络拥塞也要一往无前。

1.网页或者APP的访问

QUIC(快速UDP互联网连接)是Google 提出的一种基于UDP改进的通信协议,

2.流媒体协议

直播使用的RTMP协议。因为直播看中的是实时性,宁可丢包也不能卡顿。很多直播引用都是基于UDP实现了视频传输协议

3.实时游戏。

如果数据包丢了,所有事情都要停下等待这个数据包重新发送,玩家并不关心过期的数据等能够动就死了、实时游戏采用自定义的UDP协议,自定义重传策略,把丢包产生的延迟降到最低尽量减少网路问题对游戏的影响

关于上面的QUIC协议玲珑会在下一篇的http文章中详细说明😃这里先作为了解吧。

最后

这篇文章又结束了,希望给你带来启发与思考,有问题留言哦💕

其实网络世界很有趣,虽然刚开始我被那些牛批的网络名词吓到了,觉得很难理解。但是联系到生活实际发现其实也很好理解的。

也许难住我们的只是表面上抽象的名字。比如拥塞避免的图完全就可以看作中学的复合函数图像然后发现so easy,难就难在拥塞避免这四个字本身吧。只是个人对网络的一点见解,若觉得不对还请多多包涵😁

Ok,下一篇继续玲珑分享网络中一些好玩的东西~~~