前言:
大家好,我是良辰丫,我们已经学习了网络原理基础版,初步认识了网络,还学习了网络编程,了解了网络通信的各种程序,接下来我们更深入的了解网络是如何工作的.这篇文章我们主要介绍协议,UDP和TCP的一些原理.💞💞
🧑个人主页:良辰针不戳
📖所属专栏:javaEE初阶
🍎励志语句:生活也许会让我们遍体鳞伤,但最终这些伤口会成为我们一辈子的财富。
💦期待大家三连,关注,点赞,收藏。
💌作者能力有限,可能也会出错,欢迎大家指正。
💞愿与君为伴,共探Java汪洋大海。
1. 自定义协议(约定)
我们在前面的文章中初步认识了协议,现在我们来了解一下
应用层的自定义协议
.
- 应用层和数据直接相关,决定了数据要传输什么,拿到数据后如何传输.
- 应用层存在许多现有的协议(比如http),但是很多情况下还需要我们自定义协议.
- 约定应用层数据报,数据格式,就是在自定义协议.
简述一下社交软件的数据报格式如下(并非真的,只是举例让大家理解)
发送方QQ | 接收方QQ | 时间 | 内容 |
---|
那么如何约定(自定义协议)呢?我们慢慢往下看.
1.1 确定要传输哪些信息
自定义协议之前,我们需要根据需求,确定要传输哪些信息.
以购物平台为例.
传输的信息有:
- 用户id.
- 用户信息(保密处理)
- 商品信息.
- 商家信息.
- 类型
评分等.内容
上述传输的信息不是固定的,是根据产品经理的需求做的.
1.2 确定数据以怎样的格式组织(如何约定)(应用层)
其实在网络上传输的数据,本质上都是01的二进制字符串,我们需要把传输的信息整合成一个特殊的字符串.
- 属性之间需要进行分割,可以用任意符号作为分隔符,只要分割符不会影响正文内容就行.
- 约定商家之间的信息用\n进行分割.
- 约定每一个信息的结束标志为分号.
上述就是对信息做了一个约束,只要服务器与客户端对约束的条件一一对应,接收方按照上述的约定就能很好的解析数据.
1.3 常见的约定符号
在我们实际开发中,有许多特殊的格式,可以作为约定的符号,我们可以直接拿来使用,非常方便.
1.3.1 xml格式
xml格式是一种非常流行的格式,但是最近用到比较少,这是一种通过标签的形式来组织数据的.
<request>
<userId>100</userId>
<usePos>100-100<userPos>
</request>
大家可能会有疑惑,这不是和web标签非常相似嘛,为什么不直接使用web标签呢?
- web标签中每个标签都有固定的用法(大佬约定的).
- xml中的标签都是用户自定义的,每个标签的名字都是自己取得.
1.3.2 json格式(目前常用)
使用大括号作为标识.
- 大括号里面是若干个键值对.
- 每个键值对之间使用逗号分割.
- 键和值之间使用冒号分割.
- 键必须是字符串.
- 值可以是数字,字符串,数组,甚至是另一个json等.
数据组织方式有很多,比较常见的是xml和json,咱们也先简单了解一下这两种.
2. 传输层的协议
2.1 UDP数据报
以UDP为例,来简单看一下UDP的报文格式,好多教材书的UDP报文格式如下,但是下图并不是那么准确.
下面为一个完整的应用层报文.
前四个为UDP报头.
源端口 | 目的端口 | 报文长度 | 校验和 | UDP正文/载荷 |
---|---|---|---|---|
2字节 | 2字节 | 2字节 | 2字节 |
- 每个端口号在UDP报文中,占两个字节,端口号的取值范围为0-65535.
- 一个UDP报文的最大长度就是64kb(根据65535得来的).
UDP报文的最大长度那么小,为什么不扩一下呢?
- UDP是在操作系统内核中实现,要想扩容,必须升级系统,全世界的主机都需要升级,是非常麻烦的.
- 最大长度小,需要传输一个较大的数据,怎么办呢?可以把一个数据拆分成多个部分,使用 UDP数据报来进行数据传输,可行但是比较麻烦;我们还可以使用TCP,因为TCP没有限制.
2.2 校验和
- 网络传输不一定永远那么稳定,可能会出现我们想象不到的错误,通过电信号的形式进行传输数据,电信号使用高低电频表示,如果出现一些情况情况的影响,传输数据可能就会出错.
- 校验和就是为了检测是否出错了.
老师让去书店买四本书,这个四就可以看做一个校验和,买了三本是时候,我们可以回忆道缺一本,肯定错了.买了四本,此时也不一定买对了.那么我们可以得到以下结论.
- 如果校验和不对.此时你的数据一定不对.
- 如果你的校验和对,你的数据也不定完全正确,也有一定的概率错误.
校验和使用流程如下:
- 发送方把载荷数据代入到校验和算法中,计算生成校验和结果m.
- 发送方然后把这一串数据发送给接收方.
- 接收方收到的数据,既有载荷,也有校验和m.
- 接收方就可以按照同样的算法,再计算一次校验和,得出结果n.
- 然后接收方比较m与n是否相同.
- 如果不相同,数据一定有问题.
咱们约定的是只比较校验和的结果,m和n不一样的时候就认为数据有问题,即使数据没问题,我们也认为有问题.- 校验和的计算通常用循环冗余检测法,在这里咱们简单了解一下即可.
2.2 TCP原理
在前面的文章中我们已经简单的认识了TCP的基本特性.
- 有连接.
- 可靠传输.
- 面向字节流.
- 全双工.
以前已经提到这些性质了,我这里还是简单的列举出来,因为是重点,哈哈哈.
其中,TCP最重要的特性是可靠传输
,这是TCP存在的初心,非常重要的机制.
接下来我们介绍一下TCP的几个机制,保证可靠传输的机制.
2.2.1 确认应答
确认应答
是实现可靠性最核心的机制.
A向B发一个消息,B向A做出回应,做出的回应就是
应答报文(ACK)
,我们叫做ACK报文.
有时候网络不稳定会出现后发先至的情况,连发好几条消息,不按照应有的顺序,尤其是当接收方做回应的时候出现错误,就不能很好的知道哪几条消息相匹配.
- 为了解决这个问题,我们给每条信息进行编号,于是,我们又引入了
确认序号
的概念,每条应答报文都有一个确认信号.- TCP其实对每个字节都进行编号.
确认序号的规则
- 确认序号取的是发送方发送方发过来的所有数据,最后一个字节的下一个序号.
- 确认序号的含义,在它之前的数据已经收到,接下来向发送方索要从确认序号开始的数据.
- 这样接收方就可以通过ack的确认序号,告诉发送方的哪些信号已经收到了.
TCP如何处理后发先至的情况?
- TCP会有一个接收缓冲区(一块内核中的内存空间),每个socket都有一份自己的缓冲区.
- TCP可以按照序号针对收到的消息进行整队了(这也是TCP序号的一个及其重要的用途)
2.2.2 超时重传
丢包是我们经常遇到的问题.
- 一个转发设备,承担着许多转发任务,每个设备的转发能力都是有限的.
- 当流量达到上限的时候,就可能引起数据丢包.
- 刷视频不敏感,因为视频具有缓存功能;打游戏会有感觉,卡一下,就会影响游戏体验.
- 如果包丢了接收方就收不到了,自然就不会返回ack.
- 发送方在一定时间内拿不到应答报文,就认为刚刚发的数据丢包了.
- 这样发送方就会重新发送,这就是
超时重传.
- 网络丢包是概率性事件,上个包丢了,重传往往会传过去的,因为丢包的概率很小.
发送方对于丢包的判定:
- 数据丢了,接收方没有收到,自然不会发ack.
- 接收方收到数据了,但是ack丢了.
那么,发送方根本区分不了是上述哪种情况,因此只能重传.
如果是ack丢了,数据没有丢,那么重传不会有重复的数据嘛?
TCP有一个接收缓冲区,会根绝缓冲区的数据的序号自动去重,这样就保证了应用程序读到的数据只有一份.
重传也会出现数据丢包,如果连续重传数据仍然丢失,这说明你的网络有一定的问题.TCP的宗旨是能重传就重传,重传不了就关闭连接,尽最大可能完成传输.
- TCP针对多个包丢失,处理的办法是继续超时重传.
- 但是如果丢包异常,超时等待时间就会变长(重传的频率降低了).
- 连续多次重传,都无法得到ack,此时TCP就会尝试重置连接(尝试重连)
- 如果重置连接也失败,TCP就会关闭连接,放弃网络通信了.
确认应答与超时重传是TCP可靠性的基石.
- 顺利发送消息,使用确认应答保证可靠性.
- 出现丢包,使用超时重传作为补充,有效的提高了消息接收的概率.
2.2.3 连接管理
2.2.3.1 三次握手
TCP是如何实现可靠性的?
- 我们可以回答确认应答+超时重传.
- 很多人往往回答三次握手与四次挥手,这往往是不准确的.
握手
指的是通信双方进行一次网络交互,这就相当于客户端与服务器之间,通过三次交互,真正建立了连接(双方各自记录对方的信息)
syn
称为同步报文段,意思就是一方向另一方申请建立连接(也就是验证自己能否把消息发送过去).- 这时接收方向发送方发送syn/ack,这表示我同意与你建立连接.(发送确认应答表示发送方能发送过去消息,syn也是证明接收端能否发送消息.)
- 第三次,发送端发送ack表示接收端也没问题.
双方都确认了自己没问题,于是可以实现正常的网络通信.
其实三次握手就是一个投石问路的过程,验证各自是否能正常与对方进行通信.(发送能力与接收能力是否正常)
两次握手可以吗?四次握手呢?
- 三次握手是一个投石问路的过程,如果只有两次握手.接收方始终不知道是否能正常把消息发送给发送方.
- 四次握手也可以,但是没有必要,浪费资源,第二次握手合并syn与sck,因为他们两个时机相同,可以一起发送.
- ACK为1时表示TCP数据报是一个应答报文.
- syn为1时表示当前数据报是一个同步报文.
2.2.3.2 四次挥手
挥手就是断开连接的过程.各自给双方发送一个结束报文.
- 建立连接一般都是由客户端发起的.
- 但是断开连接两方都有可能.
四次握手不能合并成三次嘛?
- 三次握手中,ack与syn是同一个时机触发的,都是由内核来完成.
- 四次挥手中,ack与fin是不同时机触发的.ack是内核完成的,会在收到fin的时候第一时间返回,fin是应用程序代码控制的,在调用socket的close方法的时候才会触发fin.
2.2.4 滑动窗口
TCP不仅要保证可靠性,还要保证效率,但是往往二者不能得皆.
上述图中A花费了大量的时间等待B的ack,要想提高效率,就需要缩短等待时间,批量的发送数据,一次发送多条数据,一次等待多个ack.
- 每次收到一个ack就立即发送下一条,而不是收到多条才开始发送下一条.
- 使用一份时间,等待多份ack,这样整体的效率就提升了.
- TCP再怎么提升效率,也没有UDP快.
上述过程就是
滑动窗口
.滑动窗口其实就是批量传输.
- 批量不是无限发送,而是有一定的限制,发送到一定的程度,就等待ack,因为数据量是有上限的.
- 回来一个ack就立即发送下一条,相当于批量等待的数据是一致的.
- 批量等待数据的数量,就是
窗口大小
.- 当收到的ack非常快的时候,此时狂口就会快速的往后移动.
批量发送的过程,会不会出现丢包呢?
当然会出现丢包,但是咱们要保证可靠性第一,效率第二.
1. 数据正常到达,ack丢了.
- 上述情况,相当于大多数ack丢了,这是非常高的丢包率.
- 其实上面情况只是ack丢了,但是对可靠性并没有影响.确认序号表示该序号之前数据已经收到了,后一个ack能够包含前一个ack.
- 那么,前一个ack丢了,后面的ack只要收到了,并不影响.
- 如果最后一个ack丢了,就需要超时重传了.
2. 数据丢了.
- 如果1001-2000这个数据丢了,接收方仍然会索要1001,不会因为收到了2001-3000就返回3001.
- 接下来几次的数据的ack,确认序号都是1001.
- 接收方再向发送方反复索要1001这个数据.
- 发送方会收到接收方的请求,然后重传了1001-2000这个数据.
- 当发送方把1001-2000这个数据重传,接收方收到数据后,返回的ack的确认号不是2001,因为2001之后的一些数据已经用过了,2001这个确认序号已经占用了.之后哪个确认序号没有用,它用哪个.
- 上述重传过程中,没有任何冗余的操作,丢了数据才会重传,不丢数据就不会重传,因此整体的速度是比较快的,这个重传过程也称为
快速重传
.- 滑动窗口与快速重传,是在批量传输大量数据的时候,会采取的措施,如果你只传输了少量的数据(低频的操作),就不会按照滑动窗口那样做了.它会按照确认应答与超时重传的方式.
2.2.5 流量控制
滑动窗口在批量发送的时候,窗口越大批量发送的数据越多,整体的速度就越快.但是呢?越快越好嘛?我们要把可靠传输放在第一位.
- 如果你发的太快了,瞬间会把接收方的缓冲区挤满了,接下来如果继续发送就会出现丢包问题,可靠性得不到保障,那快有什么用呢?
- 通过流量控制,本质上就是让接收方来限制一下发送的速度(或者阻塞等待).
那么具体怎样来进行流量控制呢?
在ack报文里面,有一个16位窗口大小这样的字段.
- 当ack为1的时候,ack报文的窗口大小就会生效,这里的16位狂口的值就是建议发送方发送的窗口大小.
- 接收方是如何计算窗口的大小的,它直接拿接收缓冲区的剩余空间作为窗口的大小.(接收缓冲区满了,发送方就会暂停发送了)
- 当发送方发现对方满了之后,就会暂停发送,但是仍然会每隔一段时间触发一个窗口探测报文,如果探测一会发现对方这里不是0了,这就有空间了,应用程序从socket读数据就会消费接收缓冲区的内容也就腾出空间了.
- 发送方的窗口 = 流量控制 + 拥塞控制.
2.2.6 拥塞控制
滑动窗口的大小取决于流量控制和拥塞控制.
- 流量控制:衡量接收方的处理能力.
- 拥塞控制:衡量了传输路径的处理能力.
- 传输路径上,任何一个设备,处理能力如果遇到瓶颈的话,都会对整体的传输速率产生明显影响.
- 而
拥塞控制
做的事情,就是衡量中间节点与传输的能力,有时候,每次传输,走的路径都不一样.
动态平衡
:
- 通过实验的方式,找到一个合适的发送速率.
- 开始的时候按照一个小的速率发送.
- 如果不丢包,就可以提高一下速率(扩大窗口的大小).
- 如果出现丢包,就立即把速率调小.
(反反复复重复上述过程)
上述就是拥塞窗口图,流量控制的窗口.
- 实际发送方的窗口大小 = min(拥塞窗口,流控窗口)
- 刚开始的时候,暂时不考虑流量控制的情况,刚开始传,会给一个非常小的窗口(比较小的初始速度),也就是慢开始.
- 每次翻倍,指数增长速度很快,可以让窗口在短时间内就达到一个比较大的值,快速接近当前网络传输路径的能力瓶颈.
- 增长到一定的程度的时候,出现丢包,就认为当前窗口的大小已经达到了当前路径的传输上限.
- 指数增长达到一定阈值就会变成线性增长,避免一下子突然超过上限很多,这样可以使得传输速度,逐渐接近传输上限.
- 13轮的时候又立即把窗口大小回归到一个比较小的初值,然后重复上述过程.
2.2.7 延时应答
- TCP可靠性的核心是确认应答.
- ack要发,但是有时候不是立即发,而是一会再发.
- TCP中决定传输速率的关键元素就是窗口大小.
- 其实延时应答也可以理解为阻塞,流量达到上限的时候不能立即发送确认报文,需要等待一段时间才能发送(流量恢复,拥塞得到缓和).
- 延时应答的效果,就是通过这个延时,让接收方的应用程序,趁机多消费一点数据,此时反馈的窗口大小就会更大一些,此时发送方的发送速率也就能更快一些,这样同时也能满足让接收方处理数据.
2.2.8 捎带应答
- 捎带应答基于延时应答.
- 客户端服务器之间的通信模型,通常就是一问一答的模型.
客户端服务器的通信模型:
- 一问一答,大多数服务器都这样.
- 多问一答,上传大文件.
- 一问一答,下载大文件.
- 多问多答,游戏串流.
四次挥手为什么可能会三次完成?
就是捎带应答,可能会把第二次和第三次联合起来.因为合成一个,比分成两个效率更高.
- 第二次挥手是在ack内核负责,立即返回.
- 第三次挥手是在应用程序中,通过write写的数据,通一些代码执行到才返回.
- 这两个实际本来是不相同的,但是通过延时应答,此时ack就可能等一会再发送,然后等到第三次挥手,一起发送.
2.2.9 面向字节流
粘包问题:
- 一句话其实就相当于一个应用层数据报.
- 当A给B连续发送多个应用层数据报后,这些数据报就累计到B的接收缓冲区,这样紧紧的挨在一起.此时B的应用程序在读数据的时候,就难以区分哪一个是完整的数据报.这样就很容易读出半个包/一个半的包.
数据到了接收缓冲区已经是分用过的,把TCP报头都拆掉了,只剩下应用层数据报(TCP载荷了),应用程序read的时候读不出TCP序号.
如何有效的解决粘包问题.
- 我们可以约定一个数据报以某个符号结尾,这样就可以区分哪些是完整的一句话.
- 定长的包,保证每次都按照固定的大小读取.
- 变长的包,可以在包头的位置,约定一个包总长度的字段,这样就知道了包的结束位置.
2.2.10 异常情况
1. 进程关闭/进程崩溃
进程没了.socket是文件,随之被关闭,虽然进程没了,但是连接还在,仍然可以进行四次挥手.
2. 主机关机(正常关机)
先杀死用户的所有进程.
这样也会触发四次挥手,如果挥完就释放连接;如果没有挥完,就关机了,此时对方就会重传,重传几次fin后,如果没有收到ack,尝试重置连接,如果还不行,就释放连接.
3. 主句掉电(拔电源)/网线断开
瞬间及其关机,来不及进行任何挥手操作.
- 对端是发送方,对端就会收不到ack,然后就会超时重传,紧接着重置连接,还不行的情况下就会释放连接.
- 对端是接收方,对端没法立即知道,你这边是还没来得及发新的数据,还是直接没了,TCP内置了心跳包保活机制.这样对端就会定期给咱们发一个心跳包(ping),咱们返回一个(pong);如果每个ping都有及时的pong,这个时候就说明当前对端的状况良好,如果ping过去之后,没有pong,这样几说明心跳没了,就认为是挂了.
心跳包的特点.文章来源:https://www.toymoban.com/news/detail-424114.html
- 周期性.
- 如果心跳没了,就挂了.
TCP与UDP的区别文章来源地址https://www.toymoban.com/news/detail-424114.html
- TCP是可靠的通信方式。通过TCP连接传送的数据,TCP通过超时重传、 数据校验等方式来确保数据无差错,不丢失,不重复,且按序到达;而UDP由于无需连接的原因,将会以最大速度进行传输,但不保证可靠交付,也就是会出现丢失、重复等等问题。
- TCP面向连接,通过三次握手建立连接,四次挥手解除连接;UDP是无连接的,即发送数据之前不需要建立连接,这种方式为UDP带来了高效的传输效率,但也导致无法确保数据的发送成功。
- TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流,由于连接的问题,当网络出现波动时,连接可能出现响应问题;UDP是面向报文的,UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低。
- 每一条TCP连接只能是点到点的;而UDP不建立连接,所以可以支持一对一,一对多,多对一和多对多的交互通信,也就是可以同时接受多个人的包。
- TCP需要建立连接,首部开销20字节相比8个字节的UDP显得比较大。
- TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道。
到了这里,关于【网络原理进阶篇】自定义协议,协议约定符,三次握手,四次挥手,TCP(保证可靠性机制)和UDP原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!