当前位置:   article > 正文

UDP/TCP

UDP/TCP
udp/tcp特征

udp:

  • 无连接
  • 不可靠传输
  • 面向数据包
  • 全双工

tcp:

  • 有连接
  • 可靠传输
  • 面向字节流
  • 全双工

解释:

有连接/无连接:发送消息时,对方是否必须要在线

比如我们聊天程序,我们给对方发送消息,是不管现在是否在线的,这就是无连接

但我们打电话时,必须要对方接通后才能对话,这句话有连接


可靠/不可靠传输:发送消息后,我并不知道对方是否已经接收到了消息

如果我明确知道对方接收到了发送的消息(打电话/已读功能)则是可靠传输,反之则不可靠


面向数据报/字节流:

字节流:数据传输就和流水一样,接踵而至,并不知道完整数据报的头和尾分别在哪

数据报:数据传输是以数据报单位传输的,具有一定的格式


全双工:即可以发送数据,也可以接收数据,一条网络通路是互通的


udp报头结构

udp报头共八字节,四个部分,每个部分2个字节

  • 源端口:发生信息的端口号
  • 目的端口:接收信息的端口号
  • udp报文长度:udp载荷----应用数据包的大小
  • 校验和:判断接收到的数据是否和发送的数据是否一样,如有错,直接丢弃

udp报文长度为两个字节(2^16  65535b),如果应用层数据包的大小超过了64kb怎么办?

  • 此时我们就需要在应用层的代码逻辑中,手动多次地将一个udp数据报分成多次来发送
  • 换用TCP协议,TCP协议并没有应用层数据报的大小限制

tcp报头结构

1.源/目的端口:从哪来,到哪去

2.4位tcp报文长度:这里的单位是字节,故能表示的长度大小位(0----60字节)

3.6位标志位:

  • URG:紧急指针是否有效
  • ACK:确认序号是否有效
  • PSH:提示接收端应用程序立刻从tcp缓冲区把数据读走
  • RST:对方要求重新建立连接,我们把携带此标志位的称为复位报文段
  • SYN:请求建立连接,我们把携带此标志的称为同步报文段
  • FIN:通知对方,本端要断开连接了,我们把携带此标志的称为结束报文段

4.校验和:确认发送与接收数据是否一致 (CRC)

5.十六位紧急指针:表明哪写数据是紧急数据

6.选项前的长度是固定的-----20字节选项长度 = 报文长度 - 20字节


TCP原理:
应答机制

引出:在网络传递信息时,可能会出现后发先置的情况

信息正常顺序送达:

小明---->小红:今天要不要出去玩  小红---->小明:没问题

小明---->小红:借我点钱     小红---->小明:哥稳衮


但网络传输存在后发先置的情况,其接收顺序可能会发送变化,从而变成

虽然消息2是后发的,但是它先于消息1到达,故小红回答哥稳衮,但在小明看来他是先发的消息1,故小明以为小红的回答是:

小明:今天要不要出去玩   小红:哥稳衮

小明:借我点钱   小红:没问题

此时,问题是不是变得和正常的情况完全相反了,不符合我们预期


解决:应答机制

将每条消息进行编号,响应对应序号的消息,此时,即使消息达到的顺序乱了,我们也可以对每个消息进行精准地回复

这个时候就需要用到我们tcp报文结构中的序号了,如何一条报文都是有序号的(包括应答报文),而确认序号只有应答报文才有,当ACK=1时,表示当前报文是应答报文,如果为0则表示是一个普通报文


超时重传

引出:当我们传输数据时不顺利时-------丢包(小概率事件)

  • 数据报丢失
  • 返回的ACK确认序号丢失

此时发送方是无法区分到底是哪种原因导致传输失败的,他只觉得没有接收到ack确认序号

此时TCP就会引入重传机制,并引入一个时间阈值,当发送方发送数据后等待实际超过时间阈值后还是没有收到ACK,此时就会重传一份和之前一摸一样的数据,而这个时间阈值是可配置的,没有固定


那如果重传一次数据后,又丢包了怎么办?

继续重传,当重传到一定次数后,会认为是网络故障,断开重连后再重传,如果此时还是失败,便断开连接。而具体是重传几次后重连,也是可配置的,不确定


同时,你重传的次数不同,时间阈值也随之不同

重传轮数越大,阈值越长,重传的频率越低

因为你重传的次数越多,代表你获得ACK的成功率越低,即使你重传地快,一样还是得不到ACK,白白浪费资源


故TCP的可靠运输,就是一句应答机制和超时重传机制所实现的


连接管理:
三次握手:

1.连接流程:

A发生SYN向B请求建立连接,B接收到请求后返回给A一个ACK,同时发生一个SYN请求和A建立连接,A接收到B的请求后返回给B一个ACK

2.这里实际上是4个步骤,为什么只有三步呢?

其实就是把B向A返回的ACK和SYN合并到一起了

3.那么为什么要合并呢?

封装分用一次的成本无疑比封装分用两次的成本低


三次挥手的意义

1.确认彼此都是对方交流的对象

2.确认彼此的接收发送功能都是正常的

3.在三次握手的过程中,可以来商讨一些彼此之间的秘密


四次挥手:

挥手流程:

1.A向B发送FIN报文,此时A进入FIN_WAIT_1状态

2.B接收到FIN报文后,返回ACK,进入到CLOSE_WAIT状态

3.A接收到B的ACK应答报文后,进入FIN_WAIT_2状态

4.B处理完数据后,向A发送FIN报文,进入LAST_ACK状态

5.A接收到B发送的FIN报文后,发送ACK报文,进入TIME_WAIT状态

6.B收到ACK报文后,断开连接,此时处于CLOSE状态

7.A经过2MSL时间后,进入CLOSE状态


问题:

1.为什么挥手中间的两次操作不能像握手一样合并成一个

首先我们得知道一个点:

FIN的发送是由我们程序员自己控制的,当我们调用操作系统给的socketAPI中的close方法时,就会发送FIN报文。而ACK是内核自动发送的,当接收到FIN,内核会立即自动返回一个ACK。所以在发送ACK和FIN报文之间,存在着一个很明显的时间差。因为你程序员在调用close方法之前做了什么操作,需要多少时间都是不确定的,故这两步操作无法合并成一步,不处于同一时机


2.为什么当A收到B的FIN后是进入TIME_WAIT状态,而不是CLOSE状态?

1).由上方所述,当接收到FIN报文后内核会自动返回一个ACK,如果A直接断开连接,处于CLOSE状态。那么如果此时ACK没有顺利到B呢?此时不就造成丢包问题了

2.)充分接收B在网络中还在传输的数据--------由于FIN之前的代码业务代码都是不同的,如果在调用close方法前执行了很多业务,传送了大量数据,此时A接收到FIN后如果直接变为CLOSE状态,那么就有可能没有完整地接收B传输给A的消息


3.2MSL是什么?怎么来的?

MSL:Maximum Segment Lifetime(最大报文存活时间),根据字面意思我们就能理解了,当超过此时间后报文被消灭,连接被断开

那么为什么是2MSL--------一来一回嘛

MSL具体是多少:通常情况下,这个值是60s,但是还是具体情况具体分析,并不是一个固定值,更准确地说MSL更像一个经验值,保证了99%的数据的传输时间都不会超过MSL


三次握手和四次挥手就决定了TCP可连接的熟悉
滑动窗口(效率机制):

如果我们每发一次消息,就需要等待接收方返回ACK后,再发一条消息,此时效率是否有点慢了呢?(可以 但不快)


解决:我们一次多发几条消息,其本质是将等待时间重叠了

  1. 窗口大小:指的是无需等待返回的ACK即可发送数据的最大值如上图,此时的窗口大小就是4000,故前四个发送的请求,直接发送,无需等待ACK
  2. 收到第一个ACK后,滑动窗口就开始往后移动了。(注意:并不是需要等待全部的ACK返回才能继续发送后面的请求,而是只要ACK小于窗口大小对应的消息数时,就往后移动,使需要等待的ACK始终是4条(就上图))
  3. 操作系统为了维护这一个滑动窗口,会在发送方开辟一个发送缓冲区来记录还没有应答的数据,只有接收到ACK的数据才会被冲刷掉

问题:

1.ACK丢了

没啥事,因为确认序号的定义是:此序号前的序号全都已经确认了

比如你发送的1-1000序号包丢了,但你ACK返回了2001,此时表示1-2000的序号都已经被确认了,所以中间的确认序号丢掉几个无关大雅,只要有后续的ACK到达即可

2.数据丢了

如果此时我们的1-1000序号包丢了,1001-2000的序号包成功发送到B,此时B回给A的ACK是1,此时返回的ACK和你发送的数据包已经没啥关系了,此后B就会一值索要序号1开头的数据包,如果B发现接下来几个仍然不是1开头的数据,那么这时候就需要对1-1000序号包进行重传了-------快速重传


快速重传:在发生数据丢包时尽快重传丢失的数据包,减少网络延迟

过程:

1.当接收方收到三个连续的重传请求后,仍没有收到对应缺少的数据包

2.接收方发送快速重传请求

3.发送方接收到快速重传的请求,进入快速重传的状态模式

4.发送方立即重传最后一次发送的数据包

5.发送方停止新的数据包的发送,等待接收方的确认


流量控制----控制发送方的窗口大小

前面说到,窗口大小决定着无序等待接收方返回ACK即可发送消息的多少,故窗口大小越大,吞吐量也越大但是窗口大小能无限大下去嘛?

这显然不符实际,窗口大小太大,会大量的消耗资源,且接收端的处理能力也跟不上,发的再快也是白发,故流量控制的工作就是,根据接收方的消息处理能力,来协调发送方的发送速率


当窗口大小为0时,发送方就得停止发送数据,在暂停发送的过程中,会给B定期发送窗口探测报文,来触发查询此时的窗口大小

比如喝瓶子中的水,当水被喝完后,我会时不时地给小卖部老板打电话,问有没有进水来


在前面的TCP首部结构中,提到了一个16位的窗口大小,这表示窗口的大小最大为64kb嘛?

实际上,在选项中存在着一个窗口拓展因子M,真正的窗口大小即为窗口大小左移M位

也就是如果如果此时M为,那么实际的窗口大小为64 << 2  = 256kb


拥塞控制:考虑传输过程中中间节点的处理能力

tcp引入慢启动机制,先发少量的数据,来勘测一下目前网络传输的环境(是否拥挤)

此时引入一个概念:拥塞窗口

1.起始值为1,当收到一个ACK确认序号后,拥塞窗口+1

2.每次发送数据包的时候,将拥塞窗口大小和接收端返回给发送方的窗口大小做比较,取较小值作为实际发送的窗口


虽然叫法叫做慢启动,但其增长速度是极快的------指数级增长,为了防止其增长得过快,为其设置了一个阈值,当拥塞窗口超过此阈值的时候,不再是指数级增长,而是成线性增长

1.每当慢启动开始的时候,慢启动阈值为窗口最大值(16位)

2.当遇到少量丢包(超时重传)后,慢启动阈值会变成原来的一半,拥塞窗口也重新变成1

3.故tcp网络吞吐量是一个循环的过程,一开始逐渐增高,当遇到网络堵塞后吞吐量又变成很低,然后又依照之前的增长顺序循环

故拥塞控制的意义为:尽可能快地将数据传输给接收方,又避免给网络太大的传输压力


延迟应答:
  • 如果我们接收方收到消息后就立即返回ACK,假设此时的传输数据只有400k,而接收方的缓冲区有1M,此时的窗口大小400k远没有达到缓冲区的范围大小,使效率降低
  • 如果我们延迟一点时间再应答,这时候可能就又有新的数据传过来了,此时大小为1M,这时候接收方缓冲区就被充分利用了,返回的窗口大小也是1M,效率提高

窗口越大,网络吞吐量越大,网络传输效率越高


Nagle算法:解决tcp传输小包,降低传输效率的问题

试想:如果你的应用层数据包只有1字节,但由于tcp报头结构,其选项前首部固定的20字节,那么此时你发送的数据就是21字节,这些小包的发送会使网络出现拥塞

故该算法要求:一个TCP连接中,至多只能有一个未被确认的小分组,在该分组未被确认前不能发送其他的小分组,该算法会收集其他小分组,在某一合适时机发送出去


Nagle算法原理:MMS(最大报文长度)

  • 如果有数据要发送,且窗口大小大于MSS,或者包含FIN报文,则立即发送
  • 如果有未确认的数据,且新数据可以与未确认的数据进行合并(新数据长度+未确认数据长度 < MMS),则新数据内容可以拼接在未确认数据后面
  • 如果新数据不能与未确认数据合并,且未确认数据此时已收到ACK,那么会分别发送新数据及未确认数据
  • 如果新数据不能与未确认数据合并,且未确认数据此时还是没有收到ACK,这是会等待直到收到未确认数据的ACK后,新数据才能被发送

那么何时进行延迟应答呢? 每几个包之间进行延迟呢?

  • 每隔N个包之间:通常取2
  • 超过最大时间限制:通常取200ms

捎带应答:

还记得我们三次握手的合并吗,而这里是有概率的合并

由于我们的延迟应答机制,可能会使我们的ACK(内核调用,立即返还)和我们的业务操作变成同一时机,有概率的合并在一起返回给发送端

故延迟应答机制增加了合并的几率


面向字节流:

缓冲区:

创建tcp连接时,内核会分别创建一个发送方/接收方缓冲区

发送方:

  • 当发送数据时(write),会先进入发送方缓冲区
  • 当发送数据的长度超过缓冲区,会被拆分成多个tcp数据包发出
  • 当发送的数据少于缓冲区时,就会先在里面等待,等待后续的数据继续写入,当缓冲区长度快要满时,再一起发送出去

接收方:

  • 数据从网卡驱动到接收方缓冲区
  • 接收方通过read将数据读出来

由于缓冲区的存在,读数据和写数据不需要一一匹配

1.比如,有一个100k的数据,我可以一次100k的数据包,这样一次就能发送出去。也可以一次发10k,发10次发送出去

2.当我接收这个100k的数据时,我可以一次读100k数据,一次读完。也可以一次读10k数据,读10次读完


我们知道,tcp传输是面向字节流的,而这就会引入一个问题-------粘包问题

试想:所发送来的数据都是和水一样源源不断连续的,那么我们该如何区分每一部分数据的头和尾呢?或者说,如何看懂一篇没有任何标点符合的文章呢?


解决:约定好应用层协议,明确数据与数据之间的分界线

1.定长:确定每次传输的数据长度都是固定的,按照固定的长度解析即可

2.不定长:确定与数据内容无冲突的分隔符,每当遇到分隔符时即分割字符流数据


那么udp数据报是否会存在粘包问题呢? ------- 不存在

  1. udp是基于数据报发送的,具有消息保护边界
  2. 不能合并或拆解,发送接收的数据都是一个一个的,每一个数据报都是完整的

但udp数据报虽然不存在粘包问题,但由于其是无连接的,会存在数据丢失/重复/乱序等问题


TCP异常情况:

1.进程结束:发送FIN终止报文

2.机器重启:发送FIN终止报文

3.网络断开:此时接收端还认为连接存在,但如果接收方执行到写操作,就会立马意识到连接已经不在了,这时候接收端就会向发送端发送RST报文(请求建立连接)

即使接收端没有执行写操作,TCP内部也内置了一个保活定时器,会定期询问对方是否还在线,连接是否还处于正常状态


小结:以上就是TCP传输的主要机制,其主要作用于两个功能:传输可靠:提高性能

传输可靠:

  • 校验和
  • 序列号/确认序列
  • 应答机制
  • 超时重发
  • 传输管理(三次握手 四次挥手)

提高性能:

  • 滑动窗口
  • 流量控制
  • 拥塞控制
  • 延迟应答+Nagle算法
  • 捎带应答

欢迎大家继续完善相关内容及补充~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/522950
推荐阅读
相关标签
  

闽ICP备14008679号