@TOC


TCP/IP模型

image-20220626123223278

image-20220626123148981

一 、应用层

应用层协议包含两个工作:

  1. 明确传输信息

  2. 明确数据的组合格式

常见的几种的协议模板

1. xml

比较老牌的数据格式:可读性高,运行效率不行

<标签名>内容<标签名>

xml ,正是因为 它这个繁琐格式,导致它的热度逐渐就降低了。
因此,xml 现在很少作为 应用层协议的设计模板了。
现在使用 xml,主要是作为一些配置文件。

image-20220626124135089


2. json

json 是当下最流行的一种 设计应用层协议 的数据格式
以后在工作中是会经常用到这个

image-20220626124430057


3. Protobuffer

可读性不好,运行效率高

为了解决 json 的问题,Protobuffer 也就是应运而生。
Protobuffer 是一种二进制格式的数据。

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

传输的只是二进制的纯粹的数据。

image-20220626124836870


小结:

这里面 json 的 应用范围 要比 Protobuffer 更广

通常 开发效率 重于 运行效率的。

开发效率 包含 开发 与 调试。

如果线上环境出问题。
如果使用 json,出问题的请求和响应,一目了然。
如果使用 protobuffer,二进制数据,肯定是没有办法用眼去排查问题的。
为了解决这个问题,只有一个办法:为它专门写一个调试代码,用它去调试,这就更麻烦一些。

这就是我们所说的开发效率上的差异。


二、传输层

image-20220626131328430

传输层和网络层是操作系统内核实现好的,,程序员不需要直接和传输层打交道,但是传输层对我们来

说仍然是意义重大的!

核心功能:完成"端对端"的数据传输

进行网络编程都需要用到 socket,一旦你调用 socket,代码就进入到传输层的范畴。

如果一切顺利,就还好。

一旦代码出现一些bug。为了解决理解这些bug,传输层的一些知识就是必要的。

传输层的协议,面试也中特别爱考,TCP协议

image-20220626130838557


传输层的协议有很多,其中最常见的就是 UDP 和 TCP 协议
下面,学习 UDP 和 TCP 中的一些具体知识。


1.UDP

UDP协议端格式

image-20220626131409763

分析协议

image-20220626132643112


UDP的特点

  1. 无连接: 知道对端的IP和端口号就直接进行传输, 不需要建立连接
  2. 不可靠: 没有确认机制, 没有重传机制; 如果因为网络故障该段无法发到对方, UDP协议层也不 会给应用层返回任何错误信息
  3. 面向数据报: 不能够灵活的控制读写数据的次数和数量
面向数据报:

应用层交给UDP多长的报文, UDP原样发送, 既不会拆分, 也不会合并

UDP缓冲区:
  1. UDP没有真正意义上的发送缓冲区. 调用sendto会直接交给内核, 由内核将数据传给网络层协议进行后续的传输动作

  2. UDP具有接收缓冲区. 但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致; 如果缓冲区满了, 再到达的UDP数据就会被丢弃

  3. UDP的socket既能读, 也能写, 这个概念叫做 全双工

UDP使用注意事项:

  • 我们注意到, UDP协议首部中有一个16位的最大长度. 也就是说一个UDP能传输的数据最大长度是64K(包含UDP首部)
  • 然而64K在当今的互联网环境下, 是一个非常小的数字。如果我们需要传输的数据超过64K, 就需要在应用层手动的分包, 多次发送, 并在接收端手动拼装

image-20220626132736180


基于UDP的应用层协议

  • NFS:网络文件系统
  • TFTP:简单文 件传输协议
  • DHCP:动态主机配置协议
  • BOOTP:启动协议(用于无盘设备启动)
  • DNS:域名解析协议

2.TCP ※

TCP全称为 “传输控制协议(Transmission Control Protocol”). 人如其名, 要对数据的传输进行一个详细的控制
TCP是一个非常重要的协议,不光在实际开发中广泛使用,同时也是面试中的高频问题

TCP协议段格式

image-20220626135403702

在真正理解TCP的一些机制之前,这里面的很多信息,以目前的知识储备是无法理解的。

因此,光看报头结构,还不够!!!
还得结合TCP这里面的一些具体的工作机制,进一步理解 TCP是怎么工作

然后,才能去明确 TCP报头,这里面都在做些什么。


TCP的特点

image-20220626141556302


TCP协议的主要机制

① 确认应答(ACK)机制

确认应答

保证可靠传输的核心机制,关键就是接收方收到消息之后,给发送方返回一个应答报文(ACK)表示自己收到了

序号和确认序号:

TCP将每个字节的数据都进行了编号,即为序号

每一个ACK都带有对应的确认序号,意思是告诉发送者,我已经收到了哪些数据,下一次你从哪里开始发

image-20220626141946145

image-20220626142006923


② 超时重传机制

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

出现丢包的两种情况:

第一种::发出去的消息丢了

image-20220626142704619

第二种:另外一种情况就是 ACK 丢了,虽然对方收到了消息,但是我收不到 ACK

image-20220626142734509


TCP内部去重

如果是 ACK 丢了此时触发的超时重传,就会导致对方接收到重复的消息,TCP内部就会有一个去

重操作,接收方接收到的数据先会放到操作系统内核的"接收缓冲区"中,接收缓冲区可以视为是一个

内存空间,并且也可以视为是一个阻塞队列

收到新的数据,TCP就会根据序号,来检查这个数据是不是在接收缓冲区中已经存在了,如果不存在,就直接进去,如果存在直接丢弃

保证应用层序调用socket api 拿到的这个数据一定不是重复的。

注意:

如果重传失败,可能还会再尝试,也不会无休止的重传,连续几次重传都不行,就认为这个网络可能是遇到了严重的情况,再怎么传都不行就只能放弃了

基于上述:

确认应答和超时重传两个机制,TCP的可靠性,得到了有效的保障


③ ※ 连接管理机制 ※

连接管理也是TCP保证可靠性的一个机制

在正常情况下, TCP要经过三次握手建立连接四次挥手断开连接


三次握手(建立连接)

三次握手客户端和服务器之间,通过三次交互,完成了建立连接的过程

"握手"是一个形象的比喻。

解释:

其实一次握手,就是一次交互的过程。
就是客户端 给 服务器 发了一个数据,这就相当于一次握手。
服务器再给客户端反馈一个数据,这就是另外一次握手。
客户端 根据服务器的反馈,而进行反馈,告诉服务器,它接受到了它的反馈,
一共经历3次,就完成这个三次握手。


图解:

image-20220626154011603

核心:

image-20220626154201652

为什么是三次握手?

中间两次可以合二为一

image-20220626154347129


拓展:

我们第一次看到的那个完整的图是什么意思呢?

image-20220626154813563


三次握手什么用?

三次握手相当于投石问路

  1. 检查当前这个网络的情况是否满足可靠传输的基本条件
  2. 让双方协商一些必要信息

-> 更具体的说,可以认为三次握手其实也是在检测通信双方,发送能力和接受能力是否都正常

image-20220626155524261


如果网络不稳定怎么办?

image-20220626155636075


结论:

三次握手 对于 TCP 可靠传输来说,是非常必要的,尤其是这个“投石问路”的过程,非常重要!


典型面试题
  1. 描述 TCP 三次握手的过程。

↑上述画图


  1. 为什么握手三次?两次行不行?四次行不行?

首先,4 次是可以的,但是!没必要!

三次握手 本就是一个双向奔赴的过程,本来就是 4次交互。
前面也说到了 中间的那两次是可以合并,没必要分成两次,来降低执行效率

两次,绝对不行的。

如果是两次,意味着 服务器(乙方),只能确定它大的接收能力是正常的,发送能力是无法确定的;而客户端(甲方)的接收 和 发送能力都是正常的,

image-20220626160754842

此时,服务器对于进行可靠传输,心里是没底的。
因为它的的发送能力是无法保证的。
故,进行第三次握手,就是为了给服务器吃一个定心丸。
告诉它目前没有任何问题,放心大胆的进行后面的操作。


四次挥手(断开连接)

四次挥手,是为了释放必要的资源。

那么,4次挥手,又是怎么挥的呢?

虽然它的目的 和 三次握手 不同,但是流程非常相似!

image-20220626162515561


三次握手 和 四次挥手 的区别

image-20220626162657392


TCP协议中的状态

image-20220626163955596

image-20220626164134872


小结

TCP 虽然可靠性是最高的机制,但是TCP也会尽可能的提高效率!!

也就是说:除了刚才的可靠性之外,还回在引入其他的机制来提高传输的效率。


④ 滑动窗口机制

滑动窗口存在的意义就是在保证可靠性的前提下,尽量提高传输效率

image-20220626203532745

这样一发一收的方式性能较低, 那么我们一次发送多条数据, 就可以大大的提高性能(其实是将多个段 的等待时间重叠在一起了)

image-20220626203908020

更直观的图👇

image-20220626203954356


滑动窗口丢包怎么处理
  1. ACK 丢了
  2. 数据丢了

情况一: ACK丢了

image-20220626204649468

这种情况下, 部分ACK丢了并不要紧, 因为可以通过后续的ACK进行确认


情况二: 数据包丢了

image-20220626205038548

这里的重传只是需要把丢了的那一块数据给重传了即可,

其他已经到了的数据就不必再重传了,整体的重传效率还是比较高的(快重传)

这个快重传就像看电视剧
在这里插入图片描述

注意:

image-20220626205138968


⑤ 流量控制机制

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

在滑动窗口中,窗口越大(一次传输的数据量),传输速率也就越高。

那么,有些朋友就会这么去想:我把窗口弄得越大越好,这样的我们数据传输量就大幅度提升了。
答案:不行!

把窗口弄大,不光要考虑发送方,还得考虑接收方。
如果发送方发送的速度非常快,接收方完全就处理不过来,接收方就会把新接收到的包给丢了。
那么,发送方是不是还得重传,这就不就在浪费时间和资源嘛!


流量控制的关键,就是要能够衡量接收方的处理速度。

怎么去衡量呢?

我们有一个明确的指标。

此处,我们就直接使用接收方 接收缓冲区 的 剩余空间大小,来衡量当前接收方的处理能力。

image-20220626210305327


问题又来了:怎么使 接送速度 动态平衡

通过ACK报文来告知,剩余空间多大

image-20220626210502522


⑥ 拥塞控制机制

拥塞控制,也是滑动窗口的延伸,也是用来限制 滑动窗口 发送的速率。

拥塞控制,衡量的是 发送方到接收方,这整个链路之间,拥堵情况(处理能力)

根据这个情况,我们来去决定发送的速率是多少

image-20220626211552952


具体这个拥塞窗口是如何变化的:

image-20220626211708851

image-20220626211925617


⑦ 延迟应答机制

相当于流量控制的延伸,流量控制可以理解为刹车

使发送方,发的不要太快,延伸应答,就想在这个基础上,能够尽量的再让窗口更大一些

先画个图方便大家理解:

image-20220626212552510

延时应答,具体延时多少呢?

1、数量限制:每隔N个包就应答一次;

2、时间限制:超过最大延迟时间就应答一次


⑧ 捎带应答机制

捎带应答,又是延时应答的延伸。

在延迟应答的基础上, 我们发现, 很多情况下, 客户端服务器在应用层也是 “一发一收” 的. 意味着客户端给 服务器说了 “How are you”, 服务器也会给客户端回一个 “Fine, thank you”

那么这个时候ACK就可以搭顺风车 , 和服务器回应的 “Fine, thank you” 一起回给客户端

image-20220626212950462

客户端和服务器之间的通信,有以下几种模型:

1.一问一答:客户端发一个请求,服务器返回一个对应的响应

2.多问一答:上传文件

3.一问多答:下载文件

4.多问多答:直播~~串流…


面向字节流 => 粘包问题

首先要明确, 粘包问题中的 "包" , 是指的应用层的数据包 TCP粘包指的是粘 的是应用

层数据报,

在 TCP 接收缓冲区中,若干个 应用层数据包混在一起了,分不出来谁是谁

image-20220626213728899


怎么解决粘包问题?

image-20220626214305164


TCP异常情况

1.进程终止

image-20220626214924738

2.机器关机

在这里插入图片描述

3.机器掉电/网线断开

image-20220626215006096


面试题:

如何基于UDP协议实现可靠传输?

这个题其实就是考TCP,本质上就是在应用层基于UDP复刻TCP的机制

实现确认应答机制. 每个数据收到之后,都要反馈一个ACK(应用程序自己定义一个 ack包)

实现序号/确认序号,以及实现去重

实现超时重传

实现连接管理

要想提高效率,实现滑动窗口

为了限制滑动窗口,实现流量控制/拥塞控制

实现延时应答,捎带应答……


啥样的场景中适合使用TCP,啥样的场景中适合使用UDP

1:啥时候使用TCP? =>对可靠性有一定要求,(日常开发中的大多数情况,都基于TCP)

2:如果传输的单个数据报比较长(超过 64k) -> 首选 TCP

3:啥时候使用UDP? =>对可靠性要求不高,对于效率的要求更高(机房内部的主机之间通信,分布式系统中,广播

就是首选UDP)