当前位置:主页 > 查看内容

《趣谈网络协议》笔记——UDP,TCP

发布时间:2021-05-09 00:00| 位朋友查看

简介:TCP和UDP的区别 1. TCP是面向连接的UDP是面向无连接的。 什么叫面向连接 在互通之前面向连接的协议会先建立连接。 建立连接就是客户端和服务器之间维护交互状态的数据结构。 2. TCP提供可靠交付而UDP继承了IP包的特性不保证可靠 通过TCP连接的数据无差错不丢……

TCP和UDP的区别

1. TCP是面向连接的,UDP是面向无连接的。

什么叫面向连接?
在互通之前,面向连接的协议会先建立连接。 建立连接就是客户端和服务器之间维护交互状态的数据结构。

2. TCP提供可靠交付;而UDP继承了IP包的特性,不保证可靠

通过TCP连接的数据,无差错,不丢失,不重复,并且按序到达。
UDP不保证不丢失,不保证按序到达。

3. TCP是面向字节流的,UDP是基于数据报的

TCP是有缓冲区,UDP面向报文段是没有缓冲区的。
TCP发送报文时,是将应用层数据写入TCP缓冲区中,然后由TCP协议来控制发送这里面的数据,而发送的状态是按字节流的方式发送的,跟应用层写下来的报文长度没有任何关系,所以说是流。
UDP,它没有缓冲区,应用层写的报文数据会直接加包头交给网络层,由网络层负责分片,所以是面向报文段的。

UDP包头

在这里插入图片描述
端口号:根据端口号,将数据交给相应的应用程序。

UDP的三大特点:

  1. 沟通简单。没有大量的数据结构,包头字段,处理逻辑等。
  2. 轻信他人。不会建立连接,可以接收任何数据,也可以发送任何数据。
  3. 愣头青,不懂权变。没有拥塞控制,不管网络好不好只管发。

UDP的三大使用场景

  1. 需要的资源少,在网络情况比较好的内网,或者对于丢包不敏感的应用。

比如DHCP就是基于UDP协议的,一般获取ip地址都是内网请求,并且一次获取不到也没关系。

  1. 不需要一对一的建立连接,而是应用在广播的应用中。

UDP的不面向连接的功能,可以使得可以承载广播或者多播的协议。DHCP就是广播的形式。

  1. 需要处理的速度快,时延低,可以容忍少量的丢包,但要求即便网络拥塞也继续传输的情况。

UDP简单、处理速度快,不像TCP那样,操这么多的心,各种重传,保证顺序,前面的不收到,后面的没法处理,这样会导致时延很大。
并且在网络不好丢包的时候,拥塞控制会进一步降低发送速率,这样导致在本来卡的时候更卡了。

一些应用可以有自己的连接策略来保证可靠性(应用层保证),而通过UDP来保证时延要求。
比如:

  1. 网页或者APP的访问.

目前的HTTP协议,往往采取多个数据通道共享一个连接的情况,这样本来为了加快传输速度,但是TCP的严格顺序策略使得哪怕共享通道,前一个不来,后一个和前一个即便没关系,也要等着,时延也会加大。

QUIC(全称Quick UDP Internet Connections,快速UDP互联网连接)。是一种基于UDP改进的通信协议,其目的是降低网络通信的延迟,提供更好的用户互动体验。
QUIC在应用层上,会自己实现快速连接建立、减少重传时延,自适应拥塞控制。

  1. 流媒体协议。

很多直播软件都基于UDP实现了自己的视频传输协议。

  1. 实时游戏

游戏对实时要求较为严格的情况下,采用自定义的可靠UDP协议,自定义重传策略,能够把丢包产生的延迟降到最低,尽量减少网络问题对游戏性造成的影响。

  1. IoT物联网

一方面,物联网领域终端资源少,很可能只是个内存非常小的嵌入式系统,而维护TCP协议代价太大;另一方面,物联网对实时性要求也很高,而TCP还是因为上面的那些原因导致时延大。

TCP包头格式

在这里插入图片描述
端口号:和UDP一样,对应数据发给哪个应用。
序号:解决乱序问题。
确认序号:解决不丢包的问题,如果没收到,需要重发直到送达。
一些状态位:SYN是发起一个连接,ACK是回复,RST是重新连接,FIN是结束连接。
窗口大小:TCP要做流量控制,通信双方标明自己能够处理的能力,不要发太快也不要发太慢。除了流量控制外,还做拥塞控制,不能强人所难,控制自己的发送速度,改变不了世界,就改变自己。

因此掌握TCP协议需要掌握这几点(分别对应以上字段):
1. 顺序问题,稳重不乱
2. 丢包问题,承诺靠谱
3. 连接维护,有始有终
4. 流量控制,把握分寸
5. 拥塞控制,知进知退

TCP三次握手
首先建立一个连接,也即连接维护问题
在这里插入图片描述
因为TCP协议是全双工的,对于单链接时要保证可靠需要一问一答:

也即客户端发送SYN(sqe = x)想要建立连接,需要等待服务器的ACK(ack = x+1)回复,才能算是单方向的链接成功。

同样,服务器端到客户端建立可靠的通信链接也需要一问一答:

服务器发送SYN(sqe = y)状态位想要建立连接,需要等待客户端的ACK(ack = y+1)回复,这条单向通信链路连接成功。

而其中的服务器端回复确认ACK的时候可以一起将建立连接的SYN一起发送给客户端,最终就成了三次握手。

这里有个疑问是,如果客户端最后一次握手的ACK丢了咋办?或者服务器发送完SYN和ACK后挂了咋办?
因为在客户端与服务器建立三次握手后,客户端就会立即发送数据了,一旦客户端开始发送数据了,很多问题就迎刃而解了,此时服务器收到客户端的数据,即便没有收到前面客户端的ACK,服务器可以认为这个连接已经建立;
如果服务器挂掉了,客户端发送数据,会报错说服务器不可达,客户端就知道了服务器出问题了。(报错说服务器不可达,这是在IP层中的ICMP协议可以反馈的)。

然后又有疑问:说建立完成三次握手就紧接着发送数据,要是客户端建立连接后就是不发送数据呢?
设计程序的时候可以要求开启keepalive机制,即使没有发送数据包,也会发送探活包。当然,对于服务器端可以设计长时间客户端不发送数据,可以主动关闭。

TCP三次握手除了双方建立连接外,还有沟通双方TCP包的序号问题。

TCP四次挥手
在这里插入图片描述
四次挥手可以类比于上面说的三次握手,当客户端A想要结束连接(FIN,sqe = p)的时候,必须服务器B回复(ACK, ack = p+1)后才能单端关闭。
但是此时第二步和第三步不能合并,因为此时服务器B还依然在传送数据,还不想立即关闭连接的。
当服务器B也想要结束连接(FIN, sqe = q,ACK,ack = p+1)时候,等待客户端A回复(ACK, ack = q+1),但是客户端A回复ACK后还要等待2MSL。

为什么要等待2MSL?

  1. 如果客户端A发送完ACK后直接跑路了,可能服务器B并没有收到这个ACK,当服务器B长时间未收到ACK回复后,会重新发送,对应客户端也要重新发送回复。
  2. MSL是Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间。

如何实现一个靠谱的协议?

为了保证顺序性,TCP协议在每个包都有一个ID号,这个ID号是在三次握手建立连接的时候商定好的。为了保证不丢包,需要每个包都进行应答,但也不是接收端收到哪个就立即应答哪个,而是应答之前的某个ID,表示前面都收到了。这称为累计确认或累计应答

为了记录这些包ID,发送端和接收端分别都要有缓存来记录。

下图是发送端缓存状态的数据结构,分为四个部分:1. 发送的并且已经收到ACK确认的。2. 发送出去了但是还未收到ACK确认的部分。 3. 还没有发送,即将发送的部分。 4. 还没有发送但是超过自己能力范围的部分。

第三部分和第四部分不合在一起的原因是:前面说到的流量控制,要把握分寸,接收端做不过来就不能发送了。

在这里插入图片描述
窗口大小为:黑色加粗部分的,也即第三部分加上第四部分。

以下为接收端缓存的数据结构:分为三个部分,1. 接收到了并且已经回复ACK了,但是还没有提交给应用层的部分。2. 等待接收还没回复ACK的部分。3. 不能接收的部分,超过最大处理能力的部分。
在这里插入图片描述
窗口大小为:NextByteExpected至MaxRcvBuffer指向的区间。
也就是:AdvertisedWindow=MaxRcvBuffer - ((NextByteExpected-1)-LastByteRead)

通过上面介绍的基本的发送端和接收端的数据结构,接下来说明一下顺序问题个丢包问题的具体实现。

发送端看:1,2,3是已发送并确认的。4,5,6,7,8,9都是发送了还没确认。
接收端看:1,2,3,4,5是已经完成ACK但是应用层还没读取的,6,7是等待接收,8,9是已经接收但是没有ACK的部分。

(从这里看出来6,7没有ACK之前,8,9是不发送ACK的,对应前面的累计确认。因为一旦发送了ACK,窗口会向后滑动的,因此需要保证前面的都要ACK才可以)

例如:发送端和接收端当前的状态如下:

  • 1,2,3没有问题,双方达成了一致。
  • 4,5接收方说ACK了,但发送方还未收到,有可能丢了,有可能在路上。
  • 6,7,8,9发送方肯定都发了,但接收方是8,9已经到了,但是6,7没到,出现了乱序,缓存着但是没办法ACK。

如果发送端4的ACK接收到了,但是5的ACK丢了怎么办?
如果接收端6,7的数据包丢了怎么办?
答:超时重发。超过一定时间就重新尝试发送,这个时间的设定是根据往返时间RTT得到的,并且是根据网络情况不断变化的。由于重传时间是不断变化的,因此称为自适应自动重传算法。

因此一段时间后发送端未收到5,6,7的ACK就会重发5,6,7的数据包。接收端发现5已经之前有了就会丢弃5,并将6,7的ACK返回。

快速重传的机制,当接收方收到一个序号大于下一个所期望的报文段时,就检测到了数据流中的一个间格,于是发送三个冗余的ACK,客户端收到后,就在定时器过期之前,重传丢失的报文段。

例如,接收方发现6、8.9都已经接收了,就是7没来,那肯定是丢了,于是发送三个6的ACK,要求下一个是7,客户端收到3个,就会发现7的确又丢了,不等超时,马上重发。

流量控制问题
我们再来看流量控制机制,在对于包的确认中,同时会携带一个窗口的大小。
在窗口不变的情况下,大小固定为9,发送端收到4的确认后,窗口会右移一下,此时13包可发送。
在这里插入图片描述
此时,若发送端发送太猛,一下把10,11,12,13发送出去,之后就停止发送了,未发送部分变为0.
在这里插入图片描述
如果接收方实在处理的太慢,导致缓存中没有空间了,可以通过确认信息ACK修改窗口的大小,甚至可以设置为0,则发送方将暂时停止发送。

我们假设一个极端情况,接收端的应用一直不读取缓存中的数据,当数据包6确认后,窗口大小就不能再是9了,就要缩小一个变为8。

我们通过上面接收端缓存的数据结构发现,最大接收缓存量MaxRcvBuffer是固定的,如果应用层一直不读取数据,通过窗口的计算表达式,窗口会越来越小。

在这里插入图片描述
对应发送端的窗口大小通过接收到6的ACK携带的窗口大小信息,发送端的窗口不会整体右移,而是窗口的最左端右移一下,窗口大小从9变成8。
在这里插入图片描述
如果接收端应用层还是一直不处理数据,随着发送端收到确认包越来越多,窗口将越来越小,直至到0。
在这里插入图片描述
这就是常说的流量控制。

拥塞控制问题
拥塞控制的问题,也是通过窗口的大小来控制的。前面的滑动窗口rwnd是怕发送方把接收方缓存塞满,而拥塞窗口cwnd,是怕把网络塞满

LastByteSent - LastByteAcked <= min(cwnd,rwnd),拥塞窗口和滑动窗口共同控制发送的速度。

假设从发送端到接收端要经过4个网络设备(路由器网元什么的),每个设备处理一个包需要耗时1秒,所以到达另一端需要耗时4秒,如果发送的更加快速,则单位时间内,会有更多的包到达这些中间设备,这些设备还是只能每秒处理一个包的话,多出来的包就会被丢弃。
解决上面这个问题可以在每个中间设备上加缓存,这样处理不完的时候先放在缓存里。但是这样缓存里放的多了就会超时重传,也是个问题。

于是TCP的拥塞控制主要来避免两种现象包丢失和超时重传。一旦出现了这些现象就说明,发送速度太快了,要慢一点。但是一开始我怎么知道速度多快呢,我怎么知道应该把窗口调整到多大呢?

慢启动

如果我们通过漏斗往瓶子里灌水,我们就知道,不能一桶水一下子倒进去,肯定会溅出来,要一开始慢慢的倒,然后发现总能够倒进去,就可以越倒越快。这叫作慢启动。

一条TCP连接开始,cwnd设置为一个报文段,一次只能发送一个;当收到这一个确认的时候,cwnd加一,于是一次能够发送两个;当这两个的确认到来的时候,每个确认cwnd加一,两个确认cwnd加二,于是一次能够发送四个。可以看出这是指数性的增长。

当超过ssthresh = 65535这个值的时候,可能快满了,速度降下来,后面每收到一个确认后,cwnd增加1/cwnd(多个确认到来的时候才增加1),线性增长了。

但不断增加就会有水满则溢出现拥塞的时候,一旦丢包超时重传,cwnd会一下变回1,将高速的传输速度一下子降下来,一夜回到解放前,这种方式不太可取。
采用前面说的快速重传算法,发现中间缺了某个包,前一个包就连续发三次ACK,不会等待超时再重传,会立即重传,并且此时cwnd减半为cwnd/2,然后sshthresh =cwnd,并没有一夜回到解放前。

其实上面还会产生两个问题就是:

  1. 有时候公网上带宽没满的时候也会有丢包的情况,这时候发送端误以为拥塞了。
  2. TCP的拥塞控制要等到将中间设备都填充满了,才发生丢包,从而降低速度,这时候已经晚了。

为了优化以上两个问题采用TCP BBR拥塞算法。就是找到个平衡点,只把管道加满,不把路径上中间设备的缓存填满。可以很好的达到高带宽低时延的平衡。
在这里插入图片描述

拥塞控制是通过拥塞窗口来解决的,相当于往管道里面倒水,快了容易溢出,慢了浪费带宽,要摸着石头过河,找到最优值。

;原文链接:https://blog.csdn.net/qq_34008220/article/details/115429954
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!
上一篇:STM32学习记录——ST-LINK下载器 下一篇:没有了

推荐图文


随机推荐