🎉🎉🎉点进来你就是我的人了
博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!
人生格言:当你的才华撑不起你的野心的时候,你就应该静下心来学习!欢迎志同道合的朋友一起加油喔🦾🦾🦾
目标梦想:进大厂,立志成为一个牛掰的Java程序猿,虽然现在还是一个🐒嘿嘿
谢谢你这么帅气美丽还给我点赞!比个心
目录
一、应用层
1.应用层协议
2.协议模板及示例
二、传输层
传输层协议有很多,最常用的两个:UDP和TCP
1.UDP协议
1.1特点
2.TCP协议
2.1TCP核心十大机制
2.1.1 确认应答机制
2.1.2 超时重传机制
2.1.3 连接管理机制(三次握手,四次挥手)
2.1.4 滑动窗口机制
2.1.5 流量控制机制
2.1.6 拥塞控制机制
2.1.7延时应答机制
2.1.8 捎带应答机制
2.1.9 面向字节流 (粘包问题)
2.1.10 TCP异常
三、面试题
1.TCP和UDP的异同点
2.面试问题:基于UDP如何实现可靠传输?
一、应用层
1.应用层协议
①什么是应用层协议?
程序员根据用户需求来制定的应用内部协议
②设计一个应用层协议需要的步骤:
1.明确传输的信息
2.明确组织数据的格式
③举个例子,如何实现应用层协议的过程:
例如美团,当要实现查看用户历史订单的时候,就会涉及到数据的交互问题,因为历史订单是存于数据库中的,是由服务器(后端)来拿,这样就变成了前端(客服端)与后端(服务器)之间交互的问题。
很明显,前端和和后端是通过网络来进行交互的,而在这个交互的过程中,就要约定好,前端发什么样数据,而后端就会回应对应的数据。
2.协议模板及示例
①自定义协议
首先结合需求,分析清楚,请求响应(服务器/客户端之间)要传递哪些信息.
然后要明确传递的信息以什么样的格式进行组织
按照约定的信息,自定义一个传输格式,如下图:
而当前的设计也存在一定的问题:比如可读性太差(开发效率低),同时运行效率也不高
基于此,一些大佬设定了一些相关的模板供大家使用
②协议模板及示例:
1.xml(比较老的数据格式,现在用的比较少了)
a.格式及示例:
b.特点:
虽然利用xml大大地提高了协议的可读性,但是与此同时引入了太多的辅助信息,比如标签名。而对于一个服务器而言,最贵的硬件资源,就是网络带宽,这样,在同等层次的情况下,开销却是相当大的。一旦带宽固定,那么单位时间内的请求个数将会更少。
2.json(当前最流行的一种写法)
a.格式及示例:
b.特点:
相比于xml来说,json的可读性不仅没有降低,而且还降低了带宽。但是在传输过程中,仍然会传输一些多余的key的值,这在表示数组中是相当明显的,无疑,拓宽了带宽。
二、传输层
传输层实际上是不直接和程序员打交道的,但是由于网络编程会用到socket,一旦我们利用socket进入代码内部调解bug的时候就进入了传输层,所以传输层对于我们来讲仍然是至关重要的,其中最核心的知识点便是TCP协议。
传输层协议有很多,最常用的两个:UDP和TCP
1.UDP协议
学习一个协议,首先得研究它的报文格式。
1.1特点
①UDP报文格式:
②分析一下局部特点:
1.报文长度可以更改为4个字节吗?
不可以。
报文长度是2个字节,范围0-65535(0-64k)对于64k而言,是大还是小呢?对于当代互联网来说,64k是相当小的。这也就揭示了UDP数据报的一个致命的缺陷,就是当面临需要传入较大数据的时候,只能进行分包处理(把一个数据报拆成多个部分),接收方再对接收到的多个部分来进行拼接成新的完整的数据。
而这样子是不好的,毕竟在拼接的过程中,要是出现丢包或者包拼接顺序的情况的话就是相当麻烦的。所以在实际生活中,对于数据量较大的而言,我们通常用TCP来完成。
而解决方案就是,利用TCP(理由我们会在下文进行讲解)
2.校验和具体是怎么来进行校验的?
a.为什么要使用校验和?
在现实网络传输过程中,我们知道传递的本质是光信号和电信号,但是某些时候由于磁场等外界的干扰,就有可能导致某些传递的信息受到改变。因此我们需要通过校验和来进行校验。
b.校验和就一定准确吗?
校验和并不是一定准确的,只是从某种程度上保证了准确性,比如我们再做一道多选题的时候,答案显然是A~D不等的,但是要是老师为了提示我们,告诉我们,答案只有两个,那么这个时候,我们就会知道要是自己的答案不是两个的话,那么就说明自己做的是有问题的,那么就会直接中断当前的思路。但是就算你的选择是两个,但是仍然有误选的可能性。
因此,我们会发现,校验和正确,结果不一定一定准确,但是校验和不正确,那么结果一定不正确,当然,对于计算机而言,校验和也不一定就是指数量上的校验;在内容上进行某些处理,也可以实现校验和,无疑,这样的校验和准确性是更高的。
2.TCP协议
初步认识一下TCP的报文及其各部分
1. 源/目的端口号:表示数据是从哪个进程来,到哪个进程去;
2. 32位序号/32位确认号:后面详细讲;
3. 4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少个4字节),所以TCP头部最大长度是15 * 4 = 60
6位标志位:
URG:紧急指针是否有效
ACK:确认号是否有效
PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走
RST:对方要求重新建立连接;我们把携带RST标识的称为复位报文段
SYN:请求建立连接;我们把携带SYN标识的称为同步报文段
FIN:通知对方,本端要关闭了,我们称携带FIN标识的为结束报文段
4. 16位窗口大小:后面再说
5. 16位校验和:发送端填充,CRC校验。接收端校验不通过,则认为数据有问题。此处的检验和不但包含TCP首部,也包含TCP数据部分
6. 16位紧急指针:标识哪部分数据是紧急数据
7. 40字节头部选项:暂时忽略
2.1TCP核心十大机制
TCP中一些核心机制:
有连接
全双工
面字节流
可靠传输
前面三点都可以在代码上体现出来,但是可靠传输才是TCP最核心的机制!而引入TCP的关键原因就是为了保证可靠传输,因此TCP中很多的机制,都是围绕可靠传输来进行展开的
2.1.1 确认应答机制
①什么是确认应答机制:
是可靠传输中的核心机制。什么叫可靠,即为发送数据给对方后,能够知道对方有没有收到。其关键就是接收方收到消息之后,给发送方返回一个应答报文(ack,acknowledge),表示自己已经收到了。
1.传输消息,后发先至的情况:(通过举实例来说明)
某天,我和女朋友的聊天:
当我问一个问题的时候,如果不出现丢包的话,会这样回答:
如果当我发了多个消息,那么这个确认应答就可能会出现新的问题了:
②怎么解决后发先至这个问题?
1.对于上述例子的解决:
我们可以通过对消息进行编号,进而解决这个问题
2.TCP内部是如何实现编号的?
是针对字节来进行编号的。
结合例子进行分析:
而这个时候为什么不会后发先至呢?
这是因为同一个TCP数据报是 通过层层封装成为一个以太网数据帧,然后来进行传输的
而如上图(1~1000)就是同一个TCP数据报
而发生后发先至的是传输了多个TCP数据报,然后被封装成了对应的多个以太网数据帧,然后传输时所发生的情况
2.1.2 超时重传机制
①什么是超时重传机制?
相当于对确认应答进行了补充。确认应答是网络一切正常的时候,通过ACK通知发送方我收到了.如果出现了丢包的情况,超时重传机制就要起到效果了。
通俗一点来讲,就是你给对方发送了消息,但是却因为消息的传输过程中丢了包,而操作系统内部感知到了,触发了重传机制,就保证了对方能够收到这条消息。
按道理来讲,这个时候女朋友会收到两条重复的消息,但是要是这个是个转账操作的时候,那岂不是,相当的令人苦恼,那又该如何呢?
②去重操作:
所以在TCP内部实际上是有去重操作的。
接收方收到的数据会先放到操作系统内核的"接收缓冲区"中,接收缓冲区可以视为是一个内存空间,并且也可以视为是一个阻塞队列;收到新的数据,TCP就会根据序号,来检查这个数据是不是在接收缓冲区中已经存在了.如果不存在,就放进去;如果存在,直接丢弃。保证应用程序调用socket api拿到的这个数据一定是不重复的。应用程序感知不到超时重传的过程的。
重传一定能实现吗?
答案是否定的,如果只是网络简单的抖动了一下,那么重传大概率是会成功的(因为要是重传了好几次都不能收到ack的话,重传就会认为出现了严重的网络故障而不会成功),但要是遇到了网线断裂,断网等严重的网络故障,那么重传就不会一直进行,换言之,就不会成功。
2.1.3 连接管理机制(三次握手,四次挥手)
这个也是TCP保证可靠性的一个机制,在正常情况下,
TCP
要经过三次握手建立连接,四次挥手断开连接。1. 如何建立连接?(三次握手)
客户端和服务器之间,通过三次交互,完成了建立连接的过程,"握手"是一个形象的比喻。
客户端是主动发起连接请求的一方,客户端先发送一个SYN同步报文段给服务器。
需要双方都确认了,那么才算建立了连接。
这个过程就好像谈恋爱,两者都需要对对方进行表白,双方表白成功后,才算正式成功地在一起了。
这个时候就会有人发出疑问了,这不是四次握手吗?哪里来得三次?
又因为中间的ACK和SYN都是由内核态来同一时刻进行触发的,所以可以把两者封装在一起,形成一个整体。
中间的这两次,是一定会合二为一的。每次要传输的数据,都要经过一系列的封装和分用,才能完成传输,封装两次肯定不如封装一次来的更高效.
举个例子:就好像我同时在一家店铺买了两件衣服,那么这个时候,商家就会把这两个快递一口气发给我,从而节约了快递发货的成本。
2.TCP状态:
(TCP状态很多),这里着重给大家介绍两个状态
LISTEN
:表示服务器启动成功,端口绑定成功,随时可以有客户端来建立连接.(手机开机,信号良好,随时可以有人给我打电话);ESTABLISHED
:表示客户端已经连接成功,随时可以进行通信了。(有人给我打电话,我接听了,接下来就可以说话了);3.三次握手的作用?以及和可靠性的关系?
三次握手的作用:
具体来说,相当于投石问路的过程,检查一下当前这个网络的情况是否满足可靠传输的基本条件,让双方能够协商一些必要的信息,如果网络本身就效果非常差,强行进行TCP传输,也会涉及到大量丢包。更具体的说,可以认为,三次握手其实也是在检测通信双方,发送能力和接收能力是否都正常。
下面给大家举个例子来说明:
当我和男朋友打电话时,
当然,如果我一直没有听到女朋友的声音,那么我就会喂喂喂几次,要是几次下来,结果一样,那我就知道某地方出现了问题,我就会把电话给挂了。
至于上面说的协商,这里简单地理解一下:
比如,女朋友觉得水果捞填不饱饱肚子,说还是给你再带份面包吧。这样的过程也就叫做协商。
4.关于三次握手所涉及到的面试问题:
1.描述TCP三次握手的过程(刚刚已经讲述过了)
2.为什么要三次握手,不是两次?不是四次?
为啥不是两次?
不可以。意味着缺少最后一次,此时客户端这边关于发送接收能力正常的,情报是完整的,但是服务器这边是残缺的。服务器不知道自己的发送能力是否ok,也不知道客户端的接收能力是否ok ,此时此刻,服务器对于当下能否满足可靠传输,心里是没底的,这第三次交互,就是为了给服务器吃一个定心丸。
为啥不是四次?
可以。但没必要,反而浪费了资源,可以一次进行封装
5.如何断开连接?(四次挥手)
三次握手,就让客户端和服务器之间建立好了连接,其实建立好连接之后,操作系统内核中,就需要使用一定的数据结构来保存连接相关的信息,保存的信息其实最重要就是前面说的"五元组",而且客户端服务器都得保存五元组:源IP,源端口,目的IP,目的端口,TCP;既然保存了信息,就需要占用系统资源(内存),如果有朝一日,连接断开了(不复存在了),此时之前保存了连接信息就没意义了,对应的空间也就可以释放了。就如同正常情况下的分手,我们就应该把之前对方送的东西都销毁掉(当然这里开玩笑)。
1.三次握手和四次挥手间的区别与联系
a.三次握手:
一定是客户端主动发起的(主动发起的一方才叫客户端);
中间两次能合并。
三次握手中,B发送的ACK和SYN同一时机,就能够合并,此处的B给A发送的ACK和SYN都是操作系统内核负责进行的。
b.四次挥手:能是客户端主动发起,也可能是服务器主动发起。
中间两次有时候合并不了(有时候是能合并)。
不能合并的原因,在于B发送ACK和B发送FIN的时机是不同的;四次挥手中,B给A发的ACK是内核负责的,B给A发的FIN是用户代码负责(B的代码中调用了socket.close()方法,才会触发FIN)。如果这两操作之间的时间差比较大,就不能合并了;如果时间差比较小,这是可能会合并的(延时应答和捎带应答)。延时应答和捎带应答会在下文给大家讲到。2.两个关键的状态:
CLOSE_WAIT:
四次挥手挥了两次之后出现的状态.这个状态就是在等待代码中调用socket.close方法,来进行后续的挥手过程,正常情况下,一个服务器上不应该存在大量的
CLOSE_WAIT.如果存在,说明大概率是代码bug , close没有被执行到。
TIME_WAIT:
谁主动发起FIN,谁就进入TIME_WAIT.起到的效果就是给最后一次ACK提供重传机会,表面上看起来,A发送完ACK之后,就没有A的啥事了,按理说,A就应该销毁连接,释放资源了,但是并没有直接释放,而是会进入TIME_WAIT状态等待一段时间,一段时间之后再来释放连接,等这一会,就是怕最后一个ACK丢包!如果最后一个ACK丢包了就意味着B过一会就会重传FIN。
TIME_WAIT应该持续多久呢?
设定的时间是
2*MSL
,MSL
表示网络上任意两点之间,传输需要的最大时间。这个时间也是系统上可以配置的参数,一个典型的设置就是60 s(经验值)。TCP虽然可靠性是最高的机制,但是TCP也会尽可能的提高传输效率,这时候就有了滑动窗口.
2.1.4 滑动窗口机制
①滑动窗口的意义:
在保证可靠性的同时,提升传输效率。
②如何提升的传输效率的呢?
我们由前面的应答机制可以知道,要执行新的操作,那么必须先要收到ACK应答,如下图:
③而滑动窗口的本质:
批量发送数据,一次发一波数据然后等一波ACK ,形如下图:
而这里还需要注意的是:
“滑动”的意思并不是把N组数据的ACK都等到了,才继续向下发送,而是每等到一组,就继续向下发送。
按照上图来讲,比如等待1001到了,我们就可以向下发送新的一组(4001~5000),当然同时新增了一组等待,那么这个时候等待ack的范围2001,3001,4001,5001。
我们也当然可以通过窗口的大小来知道传输速度:窗口越大,就认为传输速度越快。(因为,窗口大了,就局部而言单位时间内等待的ACK就越多,而总的ACK时间就少了)
④在滑动窗口背景下的丢包问题,该如何重传呢?
情况一. ACK丢失:
这个时候我们要是发现后面的ACK有确认的话,就直接说明前面的ACK确认的数据已经包含其中了
情况二. 数据丢失:
这里的重传只是需要把丢了的那一块数据给重传了即可,其他已经到了的数据就不必再重传了,整体的重传效率还是比较高的!!
举个例子加深对重传的理解:
注意:
滑动窗口的窗口大小, 到底要多少合适??窗口越大, 传输效率就越高,但是内存消耗就更大.窗口越小,传输的效率就越低,内存的消耗也就小了.不仅仅是内存,还有一些东西会影响到"窗口大小"典型的,接收方的处理速率~如果接收方处理的速度快(应用程序从队列中取的速度快)如果接收方处理的速度慢(应用程序从队列中取的速度慢)此时就需要限制一下发送方的窗口大小.根据接收方的处理能力,来限制~限制的方法就是:流量控制!!
2.1.5 流量控制机制
①什么是流量控制机制?
流量控制,是滑动窗口的延伸,目的也是为了保证可靠性。
②为什么要引入流量控制机制?
因为在滑动窗口中,我们不能为了只追求传输速率而不考虑接收方的感受。当发送方的速度特别快,而接收方接收不过来的时候,就会出现丢包的情况。这个时候发送方仍然得重传。因此我们引入流量控制机制,就是为了能够衡量接收方的处理速度,此处使用接收方接收缓冲区的剩余空间大小来衡量当前的处理能力。
③图解:
我们就可以将接收方的接收缓冲区理解为生产消费模型中的阻塞队列,将发送方理解为生产者,接收方理解成消费者,那么图如下:
当然,接收缓冲区的空间大小是一定,我们不妨将其理解成一个蓄水池,这个蓄水池的作用是用来进行排水,进水,那么当快接近容量时,这个时候,出水速度>进水速度;当容量还 较大时, 出水速度<进水速度。这样一直维持着一种动态平衡的状态。
④接收方如何告知发送方,空间的大小?
利用ACK报文来进行告知!
具体遇到相应问题的图解:
2.1.6 拥塞控制机制
①阻塞控制机制的作用:
仍然是也是滑动窗口的延伸,也是限制滑动窗口的速率。
②阻塞控制衡量的内容:
从发送方到接收方整个链路之间的拥塞情况。因为A能够发送多快,不仅仅是基于B的接收速度,与整个链路的处理能力是密不可分的。而我们很难对其中一些设备进行衡量,所以拥塞控制的处理方式,就是通过“实验”来找到一个比较合适的范围。
③拥塞窗口是如何进行变化的呢?
2.1.7延时应答机制
①什么是延时应答机制?
流量控制的延伸,流量控制是让发送方发送的不要太快,而延时应答就是在这个的基础上,尽量扩大滑动窗口的大小。如果接收数据的主机立刻返回ACK应答,这时候返回的窗口可能比较小。
②我们仍用一个图例来对其进行说明:
2.1.8 捎带应答机制
①什么是捎带应答机制?
它是延时应答的延伸。
在延迟应答的基础上,客户端服务器在应用层也是 “一发一收” 的。比如我给朋友发消息:你在干嘛?朋友回复:玩游戏;那么这个时候ACK就可以搭顺风车,和服务器回应的 "玩游戏" 一起回给客户端。
因为延时应答的存在,导致ACK不一定是立即返回的,如果当前的延时应答,导致ACK的返回时机(是内核响应的)和应用代码中返回的响应(应用程序返回的)时机重合了,就可以把这个ACK和响应数据,合二为一。②常见的模型:
这个机制又是延时应答的延伸,客户端和服务器之间的通信有一下几种模型:
1.一问一答:客户端发送一个请求,服务器回复一个请求(上面这个例子就是一问一答)
2.一问多答:下载文件
3.多问一答:上传文件
4.多问多答:直播、串流等
2.1.9 面向字节流 (粘包问题)
①粘(nian/zhan)包问题:
不仅仅TCP有粘包问题其他的面向字节流的机制,也是存在的,比如读文件。
而这里的TCP粘包问题指的是应用层数据报,在TCP的接收缓冲区中若干个应用层数据报就会粘在一起,分不清谁是谁。
②图例解释:
当没有额外条件进行限制的时候,就会出现下面的情况:
③解决方案:
在应用层协议添加包的边界,比如这里用“;”来对不同的包的内容进行分割。那么这个时候读到的就是就没有问题了。
使用Java中自带的BufferedReader和BufferedWriter,也就是带缓冲区的输入字符流和输出字符流,通过写入的时候加上\n来结尾,读取的时候使用readLine按行来读取数据,这样就知道流的边界了,从而解决了粘包和半包的问题。
2.1.10 TCP异常
①进程的终止:
这个是在进程毫无防备的情况下,突然关闭进程,就类似于在任务管理器中直接关闭进程。
而TCP的连接是通过socket这个api来建立连接的socket本质上是打开一个文件,文件其实就存在于进程的PCB中的文件描述符表,每打开一个文件,文件描述符表就会增加一项,每关闭一个文件,文件描述符表就会删除一项,而此时直接杀死进程,PCB就没了,相应的里面的文件描述符表也就没了,就相当于文件自动关闭了,而这其实和手动调用socket.close()一样,也会触发四次挥手。因此这样就和正常关闭是一样的。
②机器关机:
这里的机器关机指的是通过正常流程来关闭机器,这样就会让操作系统杀死所有进程,从而关闭机器,这也就和上面的手动调用close方法是一样的,也是正常的
③机器掉电/网线断开:
这就类似于台式电脑直接拔掉电源,此时操作系统是不会有任何反应时间的,更不会有任何的处理措施,下面是两种常见的情况:
三、面试题
1.TCP和UDP的异同点
①相同点可以从它们各自的特点来进行考虑:
如:全双工
②不同点:
如:是否可靠,面向字节流还是数据报实现,是否有连接
啥样的场景中适合使用TCP,啥样的场景中适合使用UDP
1:啥时候使用TCP? =>对可靠性有一定要求,(日常开发中的大多数情况,都基于TCP)
2:如果传输的单个数据报比较长(超过 64k) -> 首选 TCP
3:啥时候使用UDP? =>对可靠性要求不高,对于效率的要求更高(机房内部的主机之间通信,分布式系统中,广播就是首选UDP)
2.面试问题:基于UDP如何实现可靠传输?
这个题其实就是考TCP,本质上就是在应用层基于UDP复刻TCP的机制
实现确认应答机制. 每个数据收到之后,都要反馈一个ACK(应用程序自己定义一个 ack包)
实现序号/确认序号,以及实现去重
实现超时重传.
实现连接管理
要想提高效率,实现滑动窗口
为了限制滑动窗口,实现流量控制/拥塞控制
实现延时应答,捎带应答,心跳机制…
文章来源:https://www.toymoban.com/news/detail-736958.html
文章来源地址https://www.toymoban.com/news/detail-736958.html
到了这里,关于TCP/UDP协议 (详解)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!