目录
一、应用层
顾名思义,与引用程序密切相关,不同的应用程序,可能会涉及不同的引用曾协议;对于程序员而言,开发代码过程中有相当一部分的工作量就是在自定义应用层协议;
如何自定义?
- 明确在客户端与服务器之间需要传输哪些信息;
- 明确数据格式;
这也意味着自定义应用层协议太灵活了,但这未必是好事;因此就有大佬为了方便像我这种的菜鸡发明了一种特定的数据传输格式:HTTP、XML、JSON;
1.1 HTTP
应用层最重要的协议,也是最常用的协议,这里先不展开讲,内容太多,后期单独出一章;
1.2 XML
古老经典的数据组织格式,虽然用的不多但还是会接触到;格式是通过“标签”的形式进行组织键值对的,标签的名字就是key,标签的内容就是value;
例如快递单号
<request>
<postion>
<start>发源地</start>
<end>目的地</end>
</postion>
<content>
<product>Airpods pro2</product>
<product>IPhone14</product>
</content>
</request>
缺点:
- 丑是真丑
- 数据一旦庞大,编写也会复杂
- 这些数据都是通过网络传输,消耗网络带宽,大量的标签导致网络带宽占用更高;
1.3 JSON
当前最流行的数据组织格式,是通过{ }组织,{ }里包含很多组键值对,键值对之间的使用”,”号隔开,键和值之间使用”:”隔开;数组内容用[ ]包裹
键只能是字符串类型;
值可以是字符串,数字,数组,json;
例如快递单号:
{
position: {
start:发源地 ,
end: 目的地
}
content: [
‘Airpods pro2’,’IPhone14’
]
}
优点:
- 可读性好
- 美观整洁
- 扩展性强
缺点
- 引入额外的字符串,传输的数据量一旦变大,会消耗更多的带宽;
二、传输层
端到端传输(重点关注起点和终点),核心协议就是 UDP协议:无连接,不可靠传输,面向数据报,全双工;和 TCP协议:有连接,可靠传输,面向字节流,全双工;
学习协议,重点就是在理解协议的报文格式
2.1 UDP协议
上图来自于教科书,但实际排版不是这样的,真实的排版如下图:
源/目的端口号:
表示数据是从哪个进程来, 到哪个进程去;
UDP长度 :
一个UDP报文长度就是0~65535,也就是0~64kb;所以当需要使用UDP来传输一个比较大的数据,就需要考虑拆包,将一个大的数据包拆成多个小的数据报;(TCP是面向字节流的,就没有对包的长度做出限制);
校验和:
检查数据是否出错了;
毕竟生活中环境复杂,可能会受到强电场,强磁场影响,因此就需要保证对方收到的数据是否正确;
UDP校验的常见算法——CRC算法:
把UDP报文的每一个字节都进行累加,加和放到两个字节的空间中(就算溢出也无所谓),最终的结果就是校验和,发送时,就先计算一个校验和,接收方按照相同规则在计算一遍,比较和发送方的校验和是否一致,若一致说明数据没有问题,不一致则有问题;
2.2 TCP协议
源/目的端口号:
表示数据是从哪个进程来, 到哪个进程去
序号、确定号(后期会讲);
4位首部长度:(数据偏移)
描述TCP报头有多长,这里说的4位是指4个bit位;
保留:
现在保留不用,占个位置,留下可扩展的空间;
6位标志位:
URG: 紧急指针是否有效 1为紧急标志位;
ACK: 确认号是否有效;
PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走;
RST: 对方要求重新建立连接; 我们把携带RST标识的称为复位报文段;
SYN: 请求建立连接; 我们把携带SYN标识的称为同步报文段;
FIN: 通知对方, 本端要关闭了, 我们称携带FIN标识的为结束报文段;
选项:
选项可有可无,可以有一个选项,也可以有多个,TCP报头前20个字节时固定的,后面的选项是可变的,选项可以是0~40个字节;
以上所写,仍有很多属性,不太明确,接下来进一步理解;
2.3 确认应答机制(TCP保证可靠性的核心机制)
例如A对B发送信息,B接到消息后给予反馈,也对A发送了一条消息:“收到”;
通过A有没有接收到B的消息,就可以知道上次发送的数据是成功还是失败了;回复的“收到”就是“应答报文”, 也称ack报文(6个特殊标志位中其中一位),ack -> acknowledge(应答);
普通报文ack这一位是0,应答报文这一位是1;
在确认应答机制中,引入序列号保证不出现歧义(32位序号:针对请求进行编号;32位确认号:针对ACK报文有效)
例如A对B发送两条消息,分别是两不同的请求,那么B在响应时,如何能对的上号呢?引入序列号来保证不出现歧义;
如下图:(有歧义)
如下图:(无歧义)
TCP是一个字节流协议,编号也是以字节为单位进行编号的;
例如:A对B发送“可以聊聊天吗?”报文的序列号位1,报文的长度时1000(最后一个字节的数据编号是1000)TCP报头里只能存一个序号,最后一个字节的序号是根据报文长度计算得来;B响应A:“???”是确认报文,确认序号是1001(不是1),表示含义是1001之前的数据我都收到了;
因此,序列号就是TCP对每个字节数据编得号;
确认应答是数据顺利交给对方,对方的响应,但是若传输过程中丢包该如何处理?这时就需要超时重传了;
2.4 超时重传
A对B发消息,过来很久A都没有得到B的响应,于是A就会重新发送一份;
这里无法确认丢失的是B返回给A的ACK丢失,还是A给B发送的数据丢失,所以都会重传,若丢失 ACK,那么再重新都传一遍,相当于发了两个一模一样的消息,这里B会自动将两个消息看成一个消息(去重);保证了引用层代码通过socket读取数据的数据不是重复数据;
超时时间如何确定?
系统中有个配置项是描述超时的时间阈值(没有具体参数,不同系统不一样,也可以自己配置),超过了这个时间阈值后,就会重传,若重传数据还没有响应,还会进行第二次超时重传,并且重传的时间一般比第一次更长;(超时时间并非均等,而是逐渐变大);若是网都断了,这样的重传,试多少次都没用,就会尝试重置TCP连接(断开重连),若还是连不上,直接释放连接(摆烂…);
连接管理——建立连接:
2.5 三次握手(面试必考)
双方建立相互认同关系
注意: syn为1说明这是同步报文段,尝试和对方建立连接;普通报文ack这一位是0,应答报文这一位是1;
过程:
申请建立连接,通信双方各自向对方申请,尝试和对方建立连接,然后再各自给对方回应,这个过程实际上是四次数据交互,只是将其中两个合并了;
为什么四次数据交互,却将其中两个合并了,成为了“三握”?
三次握手中,B给A返回ack是收到A给B syn之后触发的(在内核中完成的),而B给A发送syn也是内核触发(应用程序调用socket方法的write方法,把数据交给内核,内核进行封装,然后发送),也是内核触发,那么既然都是内核触发,时机完全相同(时机相同是因为——捎带应答,后面会讲到),操作系统就会将两个包合并成一个;
为什么要建立连接,连接的意义是什么?
- 检查当前网络情况是否通畅;(试探性的提前检查,建立连接并不传输任何业务数据)
- 检查通信双方的 发送能力 和 接收能力 是否都是正常;
- 协商一些重要的参数(例如TCP序号并非都是从1开始,通常都是建立连接的时候协商一个数字,目的是为了保证两个数字的序号有差别,这样就算连接断开又快速重连,接收方也可以确认当前收到的数据是上一个连接的还是当前连接的);
三次握手中两个重要的TCP状态:
LISTEN:服务器启动并且绑定了端口号后(new ServerSocket完成)表示信号良好,可以人进行传输数据;
ESTABLISHED:连接建立好后的稳定状态;
连接管理——断开连接:
2.6四次挥手
双方取消互相认关系(FIN结束报文段)
四次挥手中的中间两次有可能合并吗?
是有可能的;B给A返回ACK,是在B收到FIN立即触发的,是在操作系统内核中完成的;B继续向A发送FIN是应用程序,显示调用socket的close方法触发的;
看似不可能,实则有可能,两个数据时间都不同,为何有可能合并?
TCP一个重要机制——捎带应答;(后面具体讲,以下先讲的两个状态,便于理解)
四次挥手中三个重要状态:
CLOSE_WAIT:代码中的close操作,是接收到FIN报文时候的状态;
LAST_ACK:是被动方发送FIN报文之后置的状态;
TIME_WAIT:一个等待时间(是主动关闭乙方进入的最后一个状态,需要等待2MSL,状态才从TIME_WAIT状态变成CLOSED状态);
(主动发起关闭的一方,会进入此状态)A处理完最后一个ACK后,不会立即释放连接,而是需要一个保持时间,是为了防止最后一个ACK丢失,还有机会进行重传,如下图:
TIME_WAIT要等多久呢?
MSL:网络上两个位置之间数据消耗的最大时间;TIME_WAIT只需要等待2MSL即可;
2.7 滑动窗口
提高TCP传输效率的有效机制(简而言之):A主机连续发送n条数据给主机B,然后每次A主机每次收到一个ACK就发送一条数据;
例如下图(窗口大小为4000,以字节为单位):
解释上图:2001这个ack没来之前,主机A上待确认的数据为1001~5000,2001的ack到达以后,表示2000以上的数据都发送成功,就把1001~2000这个记录从窗口中删除,同时又发送了5001~6000这个数据,此时需要等待的数据还是4条;
问题一:主机B发送的ack中途丢失怎么办?(如下图)
即使丢失也没事,如上图中的1001的ack中途丢失,但是下一个2001成功发送了ack,这就表示2001以前的数据全部发送成功,你说妙不妙?
问题二:主机A发送的数据包中途丢失怎么办?
2.7.1 快速重传
不拖泥带水,只把丢失的包重传,没丢的包不重传;(如下图)
如上图,丢失也不用管,主机A继续自顾自往下发,主机B会不停的向A索要1001,连续几次以后,A意识到了1001丢包,就会重传1001~2000,主机B收到后,因为前面的数据B都接收到了,所以B返回ACK的确定序号为7001,A就知道什么意思了(表示7001以前的数据都收到了);
注意:只要丢包就是“超时重传”,“快速重传”可以算是“超时重传”的一种特殊情况,若传输的数据多,批量传输,就按照“快速重传”,若传输数据少(就一条)或是最后一个包丢了,就按照“超时重传”处理;
2.7.2 流量控制
滑动窗口的基础上,进行对发送速率的限制(限制窗口大小),接收方会根据自身的接收能力,来反向影响发送方“发送速率”(接收方使用接收缓冲区的剩余空间大小,作为发送速率——窗口大小,的参考数值);
问题一:怎么理解?类似蓄水池(如下图)
ACK应答报文中,就会把当前 接收缓冲区剩余的空间大小的值,反馈给对方,以控制发送速率;
TCP协议中的16位窗口大小是什么?
就是刚刚所讲到的——接收缓冲区剩余空间大小的值,并且只有在ACK位1时才有效;16位表示64kb,这并不是滑动窗口的窗口最大值,TCP报头的选项中,有一个特殊的值——“窗口大小的扩展因子”,可以通过这个来表示更大的值;
具体过程:(如下图)
2.7.3 阻塞控制
和流量控制目的一致,也是控制发送方窗口大小(但这回是控制发送方):发送速率从小开始发送,逐渐变大,若丢包,再变小…反复动态调整;
除了考虑发送方和接收方,还有什么吗?要考虑中间结点(如下图)——阻塞控制思想
TCP实现拥塞控制的具体方式是什么?
慢启动机制——发送前,网络状况未知,就少发一点;如果不丢包,就放到拥塞窗口,开始时,先指数增长(短时间弄清网络状况),达到阈值,就线性增长;(如下图)
记不住?没关系,我有办法让你记住! 往下看!
有没有发现,就像谈恋爱一样~刚开始热恋,感情温度程指数爆炸式上升,升温到一定时候,就会开始走向平淡区,升温速度程线性上升,这里的网络拥堵就像是情侣吵架了一样,感情一落千丈,回归原始,但困难总是能挺过去的,刚开始又开始程指数上升,即使没有刚开始热恋时期上升到那个点,后面感情温度程线性往下走,也所谓平平淡淡才是幸福——即使博主并没有谈过恋爱;
2.8 延时应答
基于流量控制引入的提高效率的机制;
如何理解?
想象这样一个场景,接收端的缓冲区大小为1M,一次收到了600K的数据,此时若立刻应答,那么窗口大小就是400K,但实际上那600K的数据只用了50ms很快就处理掉了;但是接收端窗口原还没有达到自己的极限,即使窗口再放大一点也能处理的过来,那么就可以让接收端晚一点再做应答,比如200ms(一般延时应答的设置时间)后,那么可能数据此时就再缓冲区已经全部被消费完了,返回的窗口大小就为1M;
窗口越大,网络吞吐量就越大,传输效率就越高.我们的目标是在保证网络不拥塞的情况下尽量提高传输效率;
另外延迟时间不一定使用时间来衡量的,也可以用传输轮次来衡量;(如下图)
2.9 捎带应答
是在延时应答基础上引入的;网络通信的经典模型就是一发一收,那么意味着主机A对主机B发送了一句“在吗?”,此时主机B回应一句“不,我不在~”,那么这个主机B回复的这条消息的时候就可以带上ACK(基于延时应答的作用下,可以同步);
捎带捎带,简单理解就是——顺便带上~
2.10 面向字节流
经典问题——“粘包问题”
主机A的应用程序从接收缓冲区中读取数据,由于是面向字节流的,因此主机A无法确定,这个数据因该从第几位开始读,读到哪一位结束;
例如:A对B发送了一句话:“做我女朋友好不好?”
B对A回复一句:“好个p”;
那么此时A可能只读到了“好” 或者 “好个” 或者……“p” ???
如何解决“粘包问题”?
1.通过分隔符,比如约定使用某一种符号比如“;”作为包的结束标志;再例如自定义应用协议,有几个典型实现:xml风额度就相当于结束标签;json分割符就相当于)……
2.通过指定包的长度,比如再数据包的开头位置声明长度;
3.TCP中的异常处理
1.程序崩溃(处理方法和普通的四次握手没有太大什么差别)
操作系统会回收进程资源,包括释放文件描述符表;就相当于socket的close,执行close就会触发FIN报文,开始进行四次挥手;
2.正常关机
系统会强制结束所有进程,和程序崩溃有点类似,内核会进行对文件描述符的释放,进一步进行四次挥手;
3.主机断电(接收方断电)
这时,发送方并不知道接收方断电,是所以继续发送,几次之后没有接收到ack回应,发送方就会触发超时重传;重传几次后还是没有应答,就会尝试重连(复位报文段:RST),又失败了,最后就放弃连接了;
4.主机断电(发送方断电)
主机等了一会,发现没反应,就会发一个“心跳包”(心跳包是周期性触发的,不携带任何业务数据的数据报,意义就是为了确认对方是否还在),若对方不返回心跳包,说明对方…挂了…也就放弃重连了;
5.网线断开
情况和主机断电一样;
4.TCP和UDP之间对比
思路:可以简单说一下各自应用场景
TCP适合对可靠性有要求的场景,十分广泛;
UDP适合对可靠性要求不高,同时对传输效率要求高的场景(例如机房内网传输,本身不容易丢包,但是对传输效率要求);
5.如何使用UPD实现可靠传输
思路:实际上考察的是TCP的可靠性的几大机制:确认应答,超时重传,引入序列号…
- 引入序列号,保证数据顺序;
- 引入确认应答,确保对端收到了数据;
- 引入超时重传,如果隔一段时间没有应答,就重发数据;
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/130423.html