网络原理详解

本文详细解析了应用层协议中的主要元素,如XML、JSON和protobuf,以及TCP/IP传输层的UDP和TCP的区别,重点介绍了确认应答、超时重传、连接管理等保证可靠性和效率的核心机制。
摘要由CSDN通过智能技术生成

应用层

在应用层中最主要的就是要约定一个“应用层协议”

在约定协议的时候主要包含两个工作:

1.明确当前的请求和响应中包含哪些信息(根据需求来~)

2.明确具体的请求和响应格式:“明确的格式”就是按照什么样的方式构造出一个字符串,后续这个字符串就可以作为TCP或者UDP的payload进行传输


虽然说自定义的格式可以是任意的,为了避免天马行空的设计,有大佬就设计出了“通用的协议格式”,咱们挑几个重要的介绍一下

1.xml

是以成对的标签,来表示“键值对”信息,同时标签支持嵌套,就可以构成更复杂的树形结构数据

xml可以很清晰地把结构化数据表示出来,但是数据要引入大量的标签,看起来比较繁琐,而且也会占用较多的网络带宽.

xml可读性比较好但运行效率不高


2.json

json是当下最流行的一种数据组织格式,本质上也是键值对,看起来会比xml干净很多

json中使用{ }表示键值对,使用[ ]表示数组;一个{ }中可以有很多个键值对;键值对之间使用逗号分隔;键与值之间使用冒号分隔;键必须是字符串类型,值可以多种类型~

json相比于xml,表示的数据简洁了许多可读性非常好,但还是需要花费一定的宽带来传输key的名字的.

json可读性很好,但运行效率不高.


3.prtobuffer

谷歌提出的一套二进制的数据序列化方式

使用二进制的方式,约定某几个字节,表示了哪个属性... 最大程度上的节省空间(不必传输key,根据长度位置,区分每个属性的)

prtobuffer节省了宽带,最大化效率;牺牲了开发效率,换来了运行效率

但prtobuffer二进制数据无法肉眼观察到,不方便调试,使用起来较复杂;要专门编写一个proto文件来面熟数据的格式是咋样的.

prtobuffer可读性不好,但运行效率很高.


传输层

前面有说到~UDP TCP

传输层UDP

UDP:无连接 不可靠传输 面向数据报 全双工 不仅仅要掌握协议的特性,还要理解报文的格式

那么2字节表示的范围究竟有多大?

以下数字都是特别常用到的数据:

        1字节:

                有符号:-128 => +127

                无符号:0 => 255

        2字节:

                有符号:-32768 => +32767

                无符号:0 => 65535

        4字节:

                有符号:-21亿 => +21亿

                无符号:0 => 42亿9千万

通过以上数据,合法的端口号有效范围就是:0-65535,不能更大了;而且实际上0不会使用的

但是互联网的发展速度太快了,能不能把这个长度改大? 不太能... 要是更改的话,咱们也得跟着改~ 但是每个人都会真的跟着改吗~

那么对于传输较大的数据时:

        1.在应用层(代码中),把数据拆成多组,通过多个UDP数据报进行传输;但是代码改动的太多了,改了之后又要重新测试,拆分传输后,对方还得拼接,怎么拼?顺序乱套了又该怎么办?万一传输的过程中又丢包了怎么办?

        2.那我们就可以使用TCP代替UDP,TCP毕竟是面向字节流 ;TCP没有要求报文长度,多长都行~

上图里还有一个校验和,校验和是怎么实现的?

使用了一种简单粗暴的CRC校验算法(循环冗余校验和):把UDP数据报中的每个字节都依次进行累加~

把累加结果保存到2个字节的变量中,加着加着就可能溢出了,溢出无所谓;所有字节都加一边,最终就得到了校验和.

传输数据的时候,就会把原始数据和校验和一起传递过去.

接收方收到数据,同时也收到了发送端送过来的校验和(旧的校验和);接收方按照同样的方式再计算一遍,得到新的校验和.

如果旧的校验和和新的校验和,相同 就可以视为数据传输过程中是正确的.如果不同反之.

数据相同 => 校验和相同

校验和相同 => 数据不同

校验和相同 => 数据相同? 不一定喔~


传输层TCP       

TCP:有连接,可靠传输,面向字节流,全双工 

保留位:暂时未启动 为了以后升级预留的空间

32位序号:
每个TCP报文段都包含一个序号字段用于标识该报文段所携带的数据块在整个数据流中的位置 发送 方在发送数据时 会给每个数据块分配一个唯一的序号 接收方在接收数据时 会根据序号来识别数据块的顺序以及是否有数据丢失或重复

32位确认序号:
接收方在接收到数据后 需要向发送方发送一个确认报文段其中包含一个确认序号字段 用于回应发送方已经成功接收到的数据的最高序号(即已经被正确接收的数据的下一个字节序号 )发送方在收到确认报文段后 就可以知道接收方已经成功接收到了哪些数据 可以继续发送下一批数据块

16位窗口大小:接收方可以接收而不会拥塞的字节数的最大值

16位紧急指针:
用于指示报文段中的紧急数据的位置,也就是报文段中紧急数据的起始偏移量。当URG标志被设置为1时,紧急指针就变得有意义了 如果没有紧急数据的话 这个紧急指针也可以不存在 一般用于一个需要快速响应的操作 例如cmd窗口中输入了ctrl+c 强制停止 就需要立即处理停止操作

选项:这个选项是可以有一个 也可以有多个 当然也可以是没有的


确认应答

保证“可靠性”最核心的机制 举个简单的例子~

那咋办?

针对数据进行编号

确认应答机制

1.针对字节进行编号,而不是针对条

2.应答报文也是要和收到的数据的序号相关联,但不是相等

如何区分当前这个报文是普通报文还是应答报文:

ACK:acknowledge

ACK为0表示这是一个普通报文 此时只有32位序号 是有效的

ACK为1表示这是一个应答报文 这个报文的序号 和 确认序号都是有效的(确认报文的序号和正常报文的序号之间没有关联关系,各论各的;序号是你自己的主机发送的数据进行编号)

核心:确认应答:是TCP保证可靠性的最核心机制!!!

           超时重传:也是TCP可靠性机制的有效补充~


超时重传机制

重传的这个时间频率也不是固定的 会随着超时轮次的增加而进一步的增加;重传的频率会逐渐降低 如果发送两次,丢包概率会大大降低~

那重传多次仍然丢包?不管咋传,都是丢的,那应该就是网线断了~

tip:确认应答机制 => 可靠性机制   不是安全机制~


连接管理

1.建立连接:三次握手 

2.断开连接:四次握手

建立连接 三次握手:

A和B完成建立连接的过程 就需要三次这样打招呼的数据交互:

经过这样的四次交互完毕 连接就算建立好了,这样双方就可以保存对端的信息了

看起来是4次 但中间这次能够合并成一次~

为什么要合并呢:封装 分用

合并之后,节省了封装和分用的过程;降低了成本,提高了效率.原则:能合并就合并~

TCP三次握手过程:

TCP的状态 (两种常见的状态)
LISTEN 表示服务器启动成功 端口绑定成功 随时可以有客户端来建立连接
ESTABLISHED 表示客户端已经连接成功 随时可以进行通信了

ACK 应答报文

SYN 申请建立连接的请求 三次握手中第一次SYN一定是客户端发起的(主动的一方)

三次握手:也是一种保证可靠性的机制~

                  就是要验证网络通信是否畅通,以及验证每个主机的发送能力及接受能力是否正常~

三次握手还起到了“信息协商”这样的效果;通信的时候会涉及到一些参数,需要双方保持一致,通过协商来决定参数具体是多少

比如双方的序号从几开始(一般不会从0 / 1开始)

这样做的保证两次连接,消息的序号能够有较大的差异,从而好去判断某个消息是否属于这个连接

综上,三次握手的初心主要两方面:

        1.投石问路,验证通信路径是否通畅,双方的发送/接收能力是否正常

        2.协商必要参数,使客户端和服务器使用相同的参数进行信息传输


断开连接 四次挥手

连接 通信双方,各自在内存中保存对端的相关信息的;如果不需要连接了,就要及时的释放上述存储空间~

6个标志位中的一个 FIN为1 就是结束报文段

三次握手一定是客户端主动发起;四次挥手不一定 服务器也可以主动发起 

四次挥手不能像三次握手 把中间的两次合并,一定不能!

因为上述的FIN的触发 是应用代码来控制的;调用socket.close(),或者进程结束就会触发FIN

相比之下,ACK是由内核控制的,收到FIN就会立刻返回ACK


讨论:如果服务器始终不进行close 会怎么样?

还有更极端的情况,比如代码写出bug,close忘记写了;站在客户端的角度,这边吃吃收不到对方的FIN,也会进行等待,如果一直等,此时就会单方面放弃连接(客户端直接把自己保存的对短信息就删了,释放了)

目标,释放资源,能双方都释放肯定是最好的,如果田间不允许,那也不影响咱们单号面释放,不能在一棵树上吊洗~


如果通信过程中,出现丢包了,又该咋处理?

还是涉及超时重传;三次握手,四次挥手 都是带有重传机制的~

尽可能重传,如果重传失败,连续多次,此时仍然会单方面释放连接~

 同理 A这边要等多久才能释放连接?

等待时间就是网络上任意两点之间传输数据的最大时间 t * 2 => 定义为 MSL

超时重传的时间必然是 <= MSL;如果超过时间达到MSL上线,此时100% 包已经丢了 超时时间设置的更大,也没啥意义了 

还有极端的情况,比如A在等2MSL时间的过程中,B在反复重传FIN多次,这些FIN都丢了(理论上存在)如果真出现了这个情况,当前网络一定是出现了严重故障了

在这个时候是不具备“可靠传输”前提条件的;因此A就单方面释放资源了~


滑动窗口

让TCP在可靠传输下,效率不要太拉跨;使用滑动窗口,不能使TCP变得比UDP快,但是可以缩小差距~

会根据原理图看出:一次性发出一组数据,发这一组数据的过程中,不需要等待ACK,直接往前发

此时就相当于“一份等待时间” 等4个ACK

把一次发多少数据,不用等ACK这样的大小,称为:窗口

窗口越大,此时批量发送的数据就越多,效率就越高

但是窗口不能无限大,相当于不必等ACK了,此时就和不可靠传输差不多了,毕竟咱是可靠传输~

按照当前批量的方式传输,中间丢包了咋办? 

两种情况:

1.数据丢了

2.ACK丢了

图解:数据丢了

图解:ACK丢了

可以理解为打怪升级,当你现在10级时,肯定(涵盖)历经了7、8级~


流量控制

滑动窗口的补充 

上述有说到 滑动窗口越大,传输效率越高,但是不可以无限大~

流量控制就是给滑动窗口踩个刹车,避免滑动窗口太大,导致接收方处理不来

流量控制的关键 就是能够衡量接收方的处理速度 此时直接使用接收方接收缓存区中剩余的大小来作为传输的效率

因此,流量控制就是根据接收方的处理能力,来限制发送方的发送速度(窗口大小)

利用接收缓冲区剩余空间大小衡量接收方的处理速度,剩余空间越大,应用程序消费数据的速度就越快~

此处就会直接把接收缓冲区剩余空间大小,通过ACK报文反馈给发送方,作为发送方下一次发送数据,窗口大小参考依据~


拥塞控制

也是滑动窗口的延申

总的传输效率是一个木桶效应,取决于短板

可以采取“实验的方式”,动态调整产出宇哥适合窗口的大小

        1.使用一个较小的窗口传输,如果传输通畅,就调整窗口大小

        2.使用一个较大的窗口传输,如果出现丢包(出现拥堵),就调小窗口

拥塞窗口:在拥塞机制下,采用的窗口大小

TCP中,拥塞控制采用以下展开:

1.慢启动:刚开始通信的时候,会采用一个非常小的窗口,先试试水

2.指数增长:在传输通常的过程中,拥塞窗口就会随指数增长(^2)(指数增长的速度极快,一定要加以限制)

3.线性增长:指数增长当拥塞窗口达到一个阀值之后,就会从指数增长转换成线性增长(+n)(线性增长也是增长,就会使发送速度越来越快,快到一定程度接近网络传输的极限,就可能出现丢包的情况了)

4.拥塞窗口回归小窗口:当窗口大小增长过程中,如果传输出现丢包,认为当前网络出现拥堵了.

        此时就会把窗口的大小调整为最初的小窗口,继续回到之前 指数增长 + 线性增长的过程

        另外此处也会根据当前出现丢包的窗口大小,调整阈值(指数增长->线性增长)

拥塞控制和流量控制都保证可靠性的机制;共同限制了滑动窗口机制,在可靠性的前提下,提高传输效率~


延迟应答

提高传输效率的机制 围绕滑动窗口琢磨的~

在需要返回ACK的时候,拖延时间,利用拖延时间就可以给应用程序腾出来更多的消费数据时间,接受缓冲区的剩余空间就会更大了~

举个例子:

那么所有的包都可以延迟应答么?肯定也不是;
数量限制:每隔N个包就应答一次;
时间限制:超过最大延迟时间就应答一次;
具体的数量和超时时间,依操作系统不同也有差异;一般N取2,超时时间取200ms;


捎带应答

在延时应答的基础上,引入第一个进一步提高效率的方式

延时应答:让ACK传输的时机更慢

捎带应答:基于延时应答,让数据进行合并


面向字节流

TCP是面向字节流的 所以不可避免的会存在粘包问题 (不仅仅是TCP存在粘包问题 其他面向字节流的机制也存在 比如读文件)
粘包问题

正确的做法:合理的设计应用层协议,在传输层就甭想了,咱们站在应用层角度解决~

1.应用层协议中,引入分隔符,区分包之间的边界

2.应用层协议中,引入“包长度”,也可以区分包之间的边界


TCP异常情况的处理

进程崩溃:

        进程就没了 => PCB就没了 => 文件描述符表也就释放了 => 相当于调用了socket.close() => 奔溃的这一方就会发出FIN,进一步的触发 四次挥手

此时连接就正常释放了;此时TCP的处理和进程正常退出,没啥区别

主机关机:

主机掉电:

网线断开:


总结:

以上TCP介绍的十个核心的特性.
1.确认应答(可靠性)
2.超时重传(可靠性)
3.连接管理(可靠性)
4.滑动窗口(效率)
5.流量控制(可靠性)
6.拥塞控制(可靠性)
7.延时应答(效率)
8.捎带应答(效率)
9.面向字节流=>粘包问题(编程注意事项)
10.异常情况处理=>心跳包(异常情况)


关于TCP 和 UDP 对比

TCP优势:可靠性 适用于绝大部分场景

UDP优势:在于效率 适用于机房内部的主机之间的通信

如何基于UDP实现可靠传输
本质上就算是再考TCP 只需要在应用层引入TCP的确认应答和超时重传机制即可

传输层的协议 只有TCP和UDP吗?
不是 在达能下常见的对抗性很高的游戏 使用的既不是TCP 也不是UDP~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值