udp是传输层最重要的协议之一。
我们先来看一下udp报文的格式
一个完整的udp应用层数据报其实就是后面的UDP载荷部分
每个端口号在UDP报文里面,取值范围在0-65535,不过< 1024的端口,称为知名端口,给一些名气较大的协议使用的,这部分端口咋们日常中不应该使用。
源ip
源端口:数据从哪里来
目的ip
目的端口:数据到哪里去
报文长度 大小是两个字节,表示的范围 0-65535=》64kB
那么UDP豹纹的最大长度就是64KB!!!
那么64KB是大还是小?
在以前64KB算是大的,但是现在很小很小。那么我们如果准备传输一个比较大的数据怎么办?
(1).把一个大数据拆分成多个部分,使用多个udp数据报来传输,但是比较复杂。
(2).不用udp,直接使用tcp,就没有限制了
注意:使用udp编程的时候,要注意udp数据报不能太长,否则会有问题。
网络传输中,并非是很稳定的,可能会出现问题。
那我们怎么判断是否出现错误呢? 这个时候就需要使用“校验和”,我们传输是通过网线传输的,也就是电信号,电信号使用高低电平表示0 1。
但是如果数据在传输过程中遭到外部环境干扰,例如强磁场之类的,就会导致 低电平->高电平 高电平->低电平。
校验和,存在的意义,就是判定一下,当前传输的数据是否出错了。
如果校验和不对,此时的数据一定不对
但是如果校验和对,但是数据也有一定的概率是错误的。
所以为了让校验和能够识别率高一点,计算的时候通常会以数据内容作为参数来进行计算,数据内容发生变化,校验和也会变化。
校验和往往是取内容一部分通过一些算术运算/数学公式变换,得到一个值
发送方,把载荷数据,带入校验和算法中,计算得到一个校验和结果,设为sum1,发送方就将这一串数据发给接收方,接收方得到的既有载荷还有校验和的值,接收方就可以把载荷按照同样的方法,在计算一遍校验和,得到sum2。我们对比sum1和sun2是否相同,如果不相同,数据就会有问题。(咋们一般使用CRC算法)。
TCP协议特点:
有连接
可靠传输:tcp存在的初心,最核心的机制
面向字节流
全双工
可靠传输:不是说100%能传过去,而是说尽可能传过去,如果传不过去,发送方至少能知道自己传没传过去。
核心机制:在于不管是否收到都会有个应答
实现可靠传输的核心机制。
发送方发送一个请求,接受方接收到以后,就会发出一个应答报文(ACK)
但是有的时候不一定会正确的对应上,可能会出现先发后至的情况。
为了解决上述问题,就需要针对消息进行编号!!给发送的消息分配一个“序号”,同时应答报文给出“确认序号”。
真实的TCp数据传输就是引入了序号和确认号。
TCP将每个字节都进行了编号,即为序列号
注意:确认序号的规则 不是说发送方的序号是啥,确认序号是啥 而是取得是发送方发来的所有数据,最后一个直接的在一个字节序号
确认序号1001的含义:
1.<1001的数据,我已经收到了
2.发送方接下里需要发送从1001开始的数据。
接收方就可以通过ack的确认序号,告诉发送发那些数据已经收到了。
如果一切顺利,那么就可以直接应答了,但是有的时候会发生丢包,丢包,也是网络上非常典型的情况。
那么为什么会丢包呢? 发送方和接收方之间是有很多节点的,任何一个节点出错都会导致丢包。每个中间设备都会承担很多转发任务,一旦任务过多,达到上限(上面的流量达到峰值)就会导致数据丢包。
如果包丢了,接收方就收不到数据,自然不会返回ack
发送方等待一段时间后,迟迟接收不到ack,那么发送方就视为数据报丢了,就会重发一遍。
丢包的判定:
1.数据直接丢了,接收方没收到,自然就不会发ack
2.接收方收到数据了,返回的ack丢了
发送方区分不了这两种情况,所以都会重传。
如果是返回的ack丢了,B会受到重复的数据,不过tcp帮助咋们解决了这个问题,接收方会在缓冲区,根据收到的数据,自动去重,保证了应用程序读到的数据只有一份。
TCp针对多个包丢失,处理思路是超时重传,但是每一次丢都会导致,超时等待时间,连续多个重传,无法得到ack就会尝试重置连接,如果重置连接也失败,TCp就会关闭连接,放弃通信了(能重传就重传,重传不了就关闭连接,尽最大可能完成传输)。
tcp怎么实现可靠性的:
确认应答
超时重传
连接管理:(tcp最核心的考点)
tcp建立连接:
三次握手 tcp
释放连接:四次挥手
上述这两个过程 和 可靠性 多少有一点关系,但不是最主要的
握手(handshake)指的是通信双方,进行一次网络交互,相当于客户端和服务器之间。进行了三次交互,建立了连接关系。
syn称为同步报文段,意思就是一方向另一方,申请建立连接
上述过程是内核自动完成的,应用程序干预不了,等连接完成了,服务器accept把建立好的连接从内核拿到应用程序。
那么设么样子的报文属于同步保温呢?
大家观察tcp报文的格式,其中有六个特殊的比特位,这几位默认是为0.
如果变为1,就是有特殊的含义
第二位ACK如果为1,表示当前tcp数据报是一个应答报文
第五位SYN如果为1,表示当前tcp数据报是一个同步报文
如果第二位和第五位都是1,那么这个报文就是ack+syn
三次握手本质上就是验证客户端和服务器,各自发送消息的能力和接受能力是否正常。
这个角度看,三次握手和可靠性,有一点关系(但是没有确认应答和超时重传重要)
四次挥手就是断开连接,通信双方,各自给对方发送一个FIN(结束报文),在各自给对方返回ACK~~
建立连接,一般是客户端先发起的
释放连接,客户端和服务端都有可能发起
为啥三次握手,能合并,四次挥手为啥不能合并?
三次握手,ack和syn都是在同一时机触发的(内核完成的)
四次挥手,ack和fin,是在不同时机触发的,ack是在内核完成的,在收到fin的时候第一时间返回~~,fin则是在应用程序控制的,再调用到socket的close方法的时候才能触发fin
tcp要保证不仅仅是可靠性还有效率,提高可靠性就代表要损失效率
如上图这样A这边就需要花费给大量的时间等待ACK,想要缩短时间就要批量发送数据,一次发送多条数据,一次等多个ack。
这就是批量发送四次数据,发完以后,统一等待ack,每次收到一个ack就立即发送下一条,使用一份时间,等待多个ack,等待时间短了,效率就高了。
UDP的效率更高,tcp再怎么提高效率,也没有UDp快。
tcp的效率机制本质就是让性能折损少一点。
上述批量传输数据的过程就称为滑动窗口
批量发送不是无限发送,是发送到一定程度就等待ack,不等待直接发送的数据是有上限的。而且是回来一个ack就立即发下一条,相当于总的要批量发送等待的数据是一致的。
批量发送的大小,就称为窗口大小
如果批量发送的过程中丢包了怎么办?
情况1:数据包到达了,ack丢了
这种情况啥事也没有,确认好的含义,就是该序列号之前的数据都收到了,后一个ack能涵盖前一个ack得意思。
就比如1-1000这个数据收到了,但是1001这个ack丢失了,但是2001这个ack收到了,那么就代表1-1000这个数据收到了,1001ack也相当于收到了。
如果最后一个ack丢包了,那么就超时重传就可以了。
情况2:数据丢了
由于1-1000这个数据丢了,所以接收方依然索要1001,不是说收到了2001-3000就返回3001,接下来的几次数据的ack都是1001,确认号都是1001,B反复向A索要1001这个数据,A连续几次收到1001之后就会知道1-1000这个数据丢了,接收方没收到,A就重传了这个数据。(这个重传过程也称为快速重传)
当A重新发送数据,B收到以后,返回的确认号是7001,而不是2001,因为中间的数据都已经收到了。
流量控制也是保证可靠性的机制
滑动窗口,窗口越大,相当于批量发送的数据就越多,但是 是越多越好吗? 如果发的太快,瞬间把接收方缓冲区给填满了,那么接下来发送就会丢包。
所以我们就会通过流量控制,本质是让接收方来限制一下发送方速度
具体怎么控制呢?让ack报文中,携带一个“窗口大小”这样的字段
当ack为1的时候,此时窗口大小字段就会生效,这里的值就是建议发送方发送的窗口大小。
那接收方怎么确定窗口大小呢?
很简单,直接拿缓冲区的剩余空间作为“窗口大小”
接收缓冲区初始剩余3000,所以发送方就会发送大小3000的数据,这个时候接收方缓冲区满了,发送方就发送不了了,等待一会(应用程序会从socket这里读取数据,读取到的数据就会从缓冲区删除,这样就腾出了空间),会发送一个窗口探测,如果发现这里不是0,就继续发送。
滑动窗口的大小=流量控制+拥塞控制
流量控制:衡量了接收方得处理能力
拥塞控制:衡量了传输路径的处理能力
很明显如果传输路径上任何一个设备有问题,对整个传输速率都是有影响的。
拥塞控制就是要衡量中间节点,传输的能力。
那么怎么衡量呢?我们通过实验的方式,找到一个合适的发送速率。
开始的时候,按照一个小的速率发送,如果不丢包就可以提高一下速率(扩大窗口大小),如果出现丢包,就立即把速率调小。每一次重复上述过程。
拥塞窗口:(拥塞控制,试验出来的窗口)
流控窗口:流量控制的窗口
实际发送发的窗口大小=min(拥塞窗口,流控窗口)
当开始是一个很小的值,开始增长,指数增长,为了让窗口大小,短时间达到一个比较大的值,接近于当前网络传输路径的能力瓶颈。
然后增长到一定的阙值,机会线性增长,为了避免突然超过上限太多,增长到一定的程度,丢包了,认定当前窗口大小,已经达到了路径的上限。这个时候就会把窗口大小回归到比较小的值,重复上述过程。
延时应答:提高传输效率
tcp可靠性的核心,是确认应答
ACK要发,但不是立即发,而是稍微等一会再发
发送发发送一个数据,正常是立即返回一个ack,ack里面有一个窗口大小,为n,
但是如果等一会在返回ack,那么里面的窗口大小,大概率会比n大
这是因为应用程序不断从缓冲区读取数据,导致缓冲区里面的数据不断减小,空间就大了。
延时应答的效果,就是通过这个延时,让应用程序多读取一些缓冲区数据,这样返回的窗口大小就会更大,发送方的发送速率就会快一些。
捎带应答是基于延时应答的
客户端服务器 通信模型:
一问一答:绝大多数服务器都是
多问一答:上传大文件
一问多答:下载大文件
多问多答:游戏串流
正常来说,A发送完数据以后,B会立即返回一个ack,随后B通过程序write写数据,在返回到A,由于这两个时机不一样,不能一起返回,不过因为延时应答就可以让ack稍微等一会,等数据一起返回,两个合并为一个,效率更高了。
为啥四次挥手,有可能三次就挥手完???同理,捎带应答的原理
粘包问题!!!
所谓一句话,就相当于一个应用层数据报
当A给B连续发送多个应用层数据报以后,这些数据就会积累在B的缓冲区中,仅仅挨在一起,此时B读取数据的时候,难以区分那到哪里是一个完整的数据报,很容易读出半个包/一个半包。
那么怎么解决呢?
1.定义分隔符:每说完一句话就以一个符号结尾,这样接受者读的时候就知道了
21.约定长度:约定数据的前四个字节表示整个数据报
1.进程关闭/进程崩溃
进程没了,socket是文件,随之被关闭,虽然进程没了,但是链接还在,依然可以继续四次挥手
2.主动关机(正常流程关机)
先杀死所有的用户进程,也会触发四次挥手,如果发挥完,更好。没有发挥完,比如对方的fin发来了,咋们还没来得及ack就关机了。
这个时候对端就会重传fin,几次过后发现没有ack传过来,就会尝试重新连接,如果还不行就会释放连接。
3.主机掉电(拔电源)
机器瞬间就关了,来不及任何操作
1)对端是发送发
对端收不到ack=》超时重传=》重置链接=》释放连接
2)对端是接收方
对端没办法立即知道,你这边是还没来得及发送数据,还是直接没了
TCp内置心跳包,保活机制
a)周期性
b)如果心跳没了,挂了~~
虽然对端是接收方,对端会定期给咱们发一个心跳包~~(ping)咱们返回一个(pong)
如果每个ping都有及时的pong,这个时候说明当前对端的状态良好如果ping过去之后,没用pong,说明心跳没了,怕是这边挂了~~
tcp可靠传输,效率没那么高:绝大多数情况下,都可以使用tcp
udp不可靠传输,效率高:对于效率高但是对于可靠性吗,没那么高(例如:同一个机房的内网之间数据传输)
如果需要效率高并且可靠的话我们就会用到其他的协议
本篇文章到这里就结束了,概念很多,大家可以收藏下来,慢慢理解,同时有很多干货是我们在面试的时候会考的。希望大家的支持。