网络原理之TCP/UDP协议

~网络原理之TCP/UDP协议_第1张图片

目录

一、应用层

1.应用层协议

2.协议模板及示例

二、传输层

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.10TCP异常

三、TCP与UDP的对比

1.异同点

2.面试问题:基于UDP如何实现可靠传输?


一、应用层

1.应用层协议

①什么是应用层协议?

程序员根据用户需求来制定的应用内部协议

②设计一个应用层协议需要的步骤

1.明确传输的信息

2.明确组织数据的格式

③举个例子,如何实现应用层协议的过程:

例如美团,当要实现查看用户历史订单的时候,就会涉及到数据的交互问题,因为历史订单是存于数据库中的,是由服务器(后端)来拿,这样就变成了前端(客服端)与后端(服务器)之间交互的问题。

很明显,前端和和后端是通过网络来进行交互的,而在这个交互的过程中,就要约定好,前端发什么样数据,而后端就会回应对应的数据。

2.协议模板及示例

①具体协议的实现

基于我们1中③的例子,我们试着来实现一个设计层

网络原理之TCP/UDP协议_第2张图片

然而,光约定了信息,只是其中的一个方面,我们还需要一定的传输格式,因此,我们通过改进,变成如下:

网络原理之TCP/UDP协议_第3张图片

而当前的设计也存在一定的问题:比如可读性太差(开发效率低),同时运行效率也不高

基于此,一些大佬设定了一些相关的模板供大家使用

②协议模板及示例:

1.xml(比较老的数据格式,现在用的比较少了)

a.格式及示例:

网络原理之TCP/UDP协议_第4张图片

 b.特点:

虽然利用xml大大地提高了协议的可读性,但是与此同时引入了太多的辅助信息,比如标签名。而对于一个服务器而言,最贵的硬件资源,就是网络带宽,这样,在同等层次的情况下,开销却是相当大的。一旦带宽固定,那么单位时间内的请求个数将会更少。

2.json(当前最流行的一种写法)

a.格式及示例:

网络原理之TCP/UDP协议_第5张图片

 b.特点:

相比于xml来说,json的可读性不仅没有降低,而且还降低了带宽。但是在传输过程中,仍然会传输一些多余的key的值,这在表示数组中是相当明显的,无疑,拓宽了带宽。

网络原理之TCP/UDP协议_第6张图片

所以我们又引入了protobuffer 

3. protobuffer

a.格式及示例:

 b.特点:

它是一种二进制格式的数据,在protobuffer的数据中,不再包含上面key的名字了,而是通过顺序以及一些特殊符号,来区分每个字段的含义,同时再通过一个IDL文件来描述这个数据格式(每个部分是啥意思), IDL只是起到一个辅助开发的效果,并不会真正的进行传输,传输的只是二进制的纯粹的数据。

但是通过示例,我们也能发现,这个样子的可读性是极低的,但我们需要调试的时候,就很难读懂,这个时候自然就降低了开发效率,而对于程序员来说,开发效率是大于运行效率的,所以在日常开发中,json更为常用

二、传输层

传输层实际上是不直接和程序员打交道的,但是由于网络编程会用到socket,一旦我们利用socket进入代码内部调解bug的时候就进入了传输层,所以传输层对于我们来讲仍然是至关重要的,其中最核心的知识点便是TCP协议。

1.UDP协议

学习一个协议,首先得研究它的报文格式。

1.1特点

①UDP报文格式:

网络原理之TCP/UDP协议_第7张图片

②分析一下局部特点:

1.报文长度可以更改为4个字节吗?

不可以。

报文长度是2个字节,范围0-65535(0-64k)对于64k而言,是大还是小呢?对于当代互联网来说,64k是相当小的。这也就揭示了UDP数据报的一个致命的缺陷,就是当面临需要传入较大数据的时候,只能进行分包处理(把一个数据报拆成多个部分),接收方再对接收到的多个部分来进行拼接成新的完整的数据。

而这样子是不好的,毕竟在拼接的过程中,要是出现丢包或者包拼接顺序的情况的话就是相当麻烦的。所以在实际生活中,对于数据量较大的而言,我们通常用TCP来完成。

网络原理之TCP/UDP协议_第8张图片

而解决方案就是,利用TCP(理由我们会在下文进行讲解) 

2.校验和具体是怎么来进行校验的?

a.为什么要使用校验和?

在现实网络传输过程中,我们知道传递的本质是光信号和电信号,但是某些时候由于磁场等外界的干扰,就有可能导致某些传递的信息受到改变。因此我们需要通过校验和来进行校验。

 b.校验和就一定准确吗?

校验和并不是一定准确的,只是从某种程度上保证了准确性,比如我们再做一道多选题的时候,答案显然是A~D不等的,但是要是老师为了提示我们,告诉我们,答案只有两个,那么这个时候,我们就会知道要是自己的答案不是两个的话,那么就说明自己做的是有问题的,那么就会直接中断当前的思路。但是就算你的选择是两个,但是仍然有误选的可能性。

因此,我们会发现,校验和正确,结果不一定一定准确,但是校验和不正确,那么结果一定不正确,当然,对于计算机而言,校验和也不一定就是指数量上的校验,内容上进行某些处理,也可以实现校验和,无疑,这样的校验和准确性是更高的。

2.TCP协议

初步认识一下TCP的报文及其各部分

网络原理之TCP/UDP协议_第9张图片

2.1TCP核心十大机制

TCP中一些核心机制:

有连接

全双工

面字节流

可靠传输

前面三点都可以在代码上体现出来,但是可靠传输才是TCP最核心的机制!而引入TCP的关键原因就是为了保证可靠传输,因此TCP中很多的机制,都是围绕可靠传输来进行展开的

2.1.1确认应答机制

①什么是确认应答机制:

是可靠传输中的核心机制。什么叫可靠,即为发送数据给对方后,能够知道对方有没有收到。其关键就是接收方收到消息之后,给发送方返回一个应答报文(ack,acknowledge),表示自己已经收到了。

1.传输消息,后发先至的情况:(通过举实例来说明)

某天,我和闺蜜的聊天:

当我问一个问题的时候,如果不出现丢包的话,会这样回答:

网络原理之TCP/UDP协议_第10张图片

 如果当我发了多个消息,那么这个确认应答就可能会出现新的问题了:

网络原理之TCP/UDP协议_第11张图片

②怎么解决后发先至这个问题?

1.对于上述例子的解决:

我们可以通过对消息进行编号,进而解决这个问题

网络原理之TCP/UDP协议_第12张图片

  2.TCP内部是如何实现编号的?

是针对字节来进行编号的。

网络原理之TCP/UDP协议_第13张图片

 结合例子进行分析:

网络原理之TCP/UDP协议_第14张图片

而这个时候为什么不会后发先至呢?

这是因为同一个TCP数据报是 通过层层封装成为一个以太网数据帧,然后来进行传输的

而如上图(1~1000)就是同一个TCP数据报

而发生后发先至的是传输了多个TCP数据报,然后被封装成了对应的多个以太网数据帧,然后传输时所发生的情况

2.1.2超时重传机制

①什么是超时重传机制?

当于对确认应答进行了补充。确认应答是网络一切正常的时候,通过ack通知发送方我收到了.如果出现了丢包的情况,超时重传机制就要起到效果了。

通俗一点来讲,就是你给对方发送了消息,但是却因为消息的传输过程中丢了包,而操作系统内部感知到了,触发了重传机制,就保证了对方能够收到这条消息。

网络原理之TCP/UDP协议_第15张图片

按道理来讲,这个时候闺蜜会收到两条重复的消息,但是要是这个是个转账操作的时候,那岂不是,相当的令人苦恼,那又该如何呢?

②去重操作:

所以在TCP内部实际上是有去重操作的。

接收方收到的数据会先放到操作系统内核的"接收缓冲区"中,接收缓冲区可以视为是一个内存空间,并且也可以视为是一个阻塞队列;收到新的数据,TCP就会根据序号,来检查这个数据是不是在接收缓冲区中已经存在了.如果不存在,就放进去;如果存在,直接丢弃。保证应用程序调用socket api拿到的这个数据一定是不重复的。应用程序感知不到超时重传的过程的。

重传一定能实现吗?

答案是否定的,如果只是网络简单的抖动了一下,那么重传大概率是会成功的(因为要是重传了好几次都不能收到ack的话,重传就会认为出现了严重的网络故障而不会成功),但要是遇到了网线断裂,断网等严重的网络故障,那么重传就不会一直进行,换言之,就不会成功。

2.1.3连接管理机制(三次握手,四次挥手)

这个也是TCP保证可靠性的一个机制,在正常情况下,TCP要经过三次握手建立连接,四次挥手断开连接。

①如何建立连接?(三次握手)

客户端和服务器之间,通过三次交互,完成了建立连接的过程,"握手"是一个形象的比喻。

客户端是主动发起连接请求的一方,客户端先发送一个SYN同步报文段给服务器。

网络原理之TCP/UDP协议_第16张图片

需要双方都确认了,那么才算建立了连接。

这个过程就好像谈恋爱,两者都需要对对方进行表白,双方表白成功后,才算正式成功地在一起了。

这个时候就会有人发出疑问了,这不是四次握手吗?哪里来得三次?

又因为中间的ACK和SYN都是由内核态来同一时刻进行触发的,所以可以把两者封装在一起,形成一个整体。

中间的这两次,是一定会合二为一的。每次要传输的数据,都要经过一系列的封装和分用,才能完成传输,封装两次肯定不如封装一次来的更高效. 

网络原理之TCP/UDP协议_第17张图片

举个例子:就好像我同时在一家店铺买了两件衣服,那么这个时候,商家就会把这两个快递一口气发给我,从而节约了快递发货的成本。 

2.TCP状态:

(TCP状态很多),这里着重给大家介绍两个状态

LISTEN:表示服务器启动成功,端口绑定成功,随时可以有客户端来建立连接.(手机开机,信号良好,随时可以有人给我打电话);
ESTABLISHED:表示客户端已经连接成功,随时可以进行通信了。(有人给我打电话,我接听了,接下来就可以说话了);

3.三次握手的作用?以及和可靠性的关系?

三次握手的作用:

具体来说,相当于投石问路的过程,检查一下当前这个网络的情况是否满足可靠传输的基本条件,让双方能够协商一些必要的信息,如果网络本身就效果非常差,强行进行TCP传输,也会涉及到大量丢包。更具体的说,可以认为,三次握手其实也是在检测通信双方,发送能力和接收能力是否都正常。

下面给大家举个例子来说明:

当我和男朋友打电话时,

网络原理之TCP/UDP协议_第18张图片

当然,如果我一直没有听到男友声音,那么我就会喂喂喂几次,要是几次下来,结果一样,那我就知道某地方出现了问题,我就会把电话给挂了。

至于上面说的协商,这里简单地理解一下:

比如,男友觉得水果捞不能填饱肚子,说还是给你再带份面包吧。这样的过程也就叫做协商。

4.关于三次握手所涉及到的面试问题:

1.描述TCP三次握手的过程(刚刚已经讲述过了) 

2.为什么要三次握手,不是两次?不是四次?

为啥不是两次?

不可以。意味着缺少最后一次,此时客户端这边关于发送接收能力正常的,情报是完整的,但是服务器这边是残缺的。服务器不知道自己的发送能力是否ok,也不知道客户端的接收能力是否ok ,此时此刻,服务器对于当下能否满足可靠传输,心里是没底的,这第三次交互,就是为了给服务器吃一个定心丸。

为啥不是四次?

可以。但没必要,反而浪费了资源,可以一次进行封装

②如何断开连接?(四次挥手)

三次握手,就让客户端和服务器之间建立好了连接,其实建立好连接之后,操作系统内核中,就需要使用一定的数据结构来保存连接相关的信息,保存的信息其实最重要就是前面说的"五元组",而且客户端服务器都得保存五元组:源IP,源端口,目的IP,目的端口,TCP;既然保存了信息,就需要占用系统资源(内存),如果有朝一日,连接断开了(不复存在了),此时之前保存了连接信息就没意义了,对应的空间也就可以释放了。就如同正常情况下的分手,我们就应该把之前对方送的东西都销毁掉。

网络原理之TCP/UDP协议_第19张图片

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*MSLMSL表示网络上任意两点之间,传输需要的最大时间。这个时间也是系统上可以配置的参数,一个典型的设置就是60 s(经验值)。

网络原理之TCP/UDP协议_第20张图片

TCP虽然可靠性是最高的机制,但是TCP也会尽可能的提高传输效率,这时候就有了滑动窗口.

2.1.4滑动窗口机制

①滑动窗口的意义:

在保证可靠性的同时,提升传输效率。

②如何提升的传输效率的呢?

我们由前面的应答机制可以知道,要执行新的操作,那么必须先要收到ACK应答,如下图:

网络原理之TCP/UDP协议_第21张图片

③而滑动窗口的本质:

批量发送数据,一次发一波数据然后等一波ACK ,形如下图:

网络原理之TCP/UDP协议_第22张图片

而这里还需要注意的是:

“滑动”的意思并不是把N组数据的ACK都等到了,才继续向下发送,而是每等到一组,就继续向下发送。
按照上图来讲,比如等待1001到了,我们就可以向下发送新的一组(4001~5000),当然同时新增了一组等待,那么这个时候等待ack的范围2001,3001,4001,5001。

网络原理之TCP/UDP协议_第23张图片
我们也当然可以通过窗口的大小来知道传输速度:

窗口越大,就认为传输速度越快。(因为,窗口大了,就局部而言单位时间内等待的ACK就越多,而总的ACK时间就少了)

④在滑动窗口背景下的丢包问题,该如何重传呢?

1.ACK丢失:

网络原理之TCP/UDP协议_第24张图片

这个时候我们要是发现后面的ACK有确认的话,就直接说明前面的ACK确认的数据已经包含其中了

2.数据丢失:

网络原理之TCP/UDP协议_第25张图片 换言之,也就是说只需要把丢失的部分进行重传,其它收到的数据不必进行,因此效率还是蛮高的。 

2.1.5流量控制机制

①什么是流量控制机制?

流量控制,是滑动窗口的延伸,目的也是为了保证可靠性。

②为什么要引入流量控制机制?

因为在滑动窗口中,我们不能为了只追求传输速率而不考虑接收方的感受。当发送方的速度特别快,而接收方接收不过来的时候,就会出现丢包的情况。这个时候发送方仍然得重传。因此我们引入流量控制机制,就是为了能够衡量接收方的处理速度,此处使用接收方接收缓冲区的剩余空间大小来衡量当前的处理能力。

③图解:

我们就可以将接收方的接收缓冲区理解为生产消费模型中的阻塞队列,将发送方理解为生产者,接收方理解成消费者,那么图如下:

网络原理之TCP/UDP协议_第26张图片

当然,接收缓冲区的空间大小是一定,我们不妨将其理解成一个蓄水池,这个蓄水池的作用是用来进行排水,进水,那么当快接近容量时,这个时候,出水速度>进水速度;当容量还 较大时, 出水速度<进水速度。这样一直维持着一种动态平衡的状态。

④接收方如何告知发送方,空间的大小?

利用ACK报文来进行告知!

网络原理之TCP/UDP协议_第27张图片

具体遇到相应问题的图解:

网络原理之TCP/UDP协议_第28张图片

2.1.6拥塞控制机制

①阻塞控制机制的作用:

仍然是也是滑动窗口的延伸,也是限制滑动窗口的速率。

②阻塞控制衡量的内容:

从发送方到接收方整个链路之间的拥塞情况。因为A能够发送多快,不仅仅是基于B的接收速度,与整个链路的处理能力是密不可分的。而我们很难对其中一些设备进行衡量,所以拥塞控制的处理方式,就是通过“实验”来找到一个比较合适的范围。

网络原理之TCP/UDP协议_第29张图片

③拥塞窗口是如何进行变化的呢?

网络原理之TCP/UDP协议_第30张图片

2.1.7延时应答机制

①什么是延时应答机制?

流量控制的延伸,流量控制是让发送方发送的不要太快,而延时应答就是在这个的基础上,尽量扩大滑动窗口的大小。如果接收数据的主机立刻返回ACK应答,这时候返回的窗口可能比较小。

②我们仍用一个图例来对其进行说明:

网络原理之TCP/UDP协议_第31张图片

2.1.8捎带应答机制

①什么是捎带应答机制?

它是延时应答的延伸。

在延迟应答的基础上,客户端服务器在应用层也是 “一发一收” 的。比如我给朋友发消息:你在干嘛?朋友回复:玩游戏;那么这个时候ACK就可以搭顺风车,和服务器回应的 "玩游戏" 一起回给客户端。
因为延时应答的存在,导致ACK不一定是立即返回的,如果当前的延时应答,导致ACK的返回时机(是内核响应的)和应用代码中返回的响应(应用程序返回的)时机重合了,就可以把这个ACK和响应数据,合二为一。

②常见的模型:

这个机制又是延时应答的延伸,客户端和服务器之间的通信有一下几种模型:

1.一问一答:客户端发送一个请求,服务器回复一个请求(上面这个例子就是一问一答)

2.一问多答:下载文件

3.多问一答:上传文件

4.多问多答:直播、串流等

2.1.9面向字节流

①粘(nian/zhan)包问题:

不仅仅TCP有粘包问题其他的面向字节流的机制,也是存在的,比如读文件。

而这里的TCP粘包问题指的是应用层数据报,在TCP的接收缓冲区中若干个应用层数据报就会粘在一起,分不清谁是谁。

②图例解释:

当没有额外条件进行限制的时候,就会出现下面的情况:

网络原理之TCP/UDP协议_第32张图片

③解决方案:

在应用层协议添加包的边界,比如这里用“;”来对不同的包的内容进行分割。那么这个时候读到的就是就没有问题了。

网络原理之TCP/UDP协议_第33张图片

2.1.10TCP异常

①进程的终止:

这个是在进程毫无防备的情况下,突然关闭进程,就类似于在任务管理器中直接关闭进程。

而TCP的连接是通过socket这个api来建立连接的socket本质上是打开一个文件,文件其实就存在于进程的PCB中的文件描述符表,每打开一个文件,文件描述符表就会增加一项,每关闭一个文件,文件描述符表就会删除一项,而此时直接杀死进程,PCB就没了,相应的里面的文件描述符表也就没了,就相当于文件自动关闭了,而这其实和手动调用socket.close()一样,也会触发四次挥手。因此这样就和正常关闭是一样的。

②机器关机:

这里的机器关机指的是通过正常流程来关闭机器,这样就会让操作系统杀死所有进程,从而关闭机器,这也就和上面的手动调用close方法是一样的,也是正常的

③机器掉电/网线断开:

这就类似于台式电脑直接拔掉电源,此时操作系统是不会有任何反应时间的,更不会有任何的处理措施,下面是两种常见的情况:

网络原理之TCP/UDP协议_第34张图片

三、TCP与UDP的对比

1.异同点

①同点可以从它们各自的特点来进行考虑:

如:全双工

②异点:

如:是否可靠,面向字节流还是数据报实现,是否有连接(这个在上节内容中讲过,这里不做详谈)

③两个问题:

1.啥时候使用TCP?

对可靠性有一定要求(大部分的开发都是这样的,基于TCP来开发)

2.啥时候使用UDP?

对可靠性要求不高,对效率要求更高一些(例如机房内的机器。因为分时操作系统对可靠性的要求相对较低)

2.面试问题:基于UDP如何实现可靠传输?

实际考点:TCP

因此我们只需要对TCP可靠传输的机制进行复刻

今天的内容就到这里啦,

下节我们继续~ 网络原理之TCP/UDP协议_第35张图片

你可能感兴趣的:(JavaEE,网络,tcp/ip,udp)