(目录)
TCP/IP模型
一 、应用层
应用层协议包含两个工作:
明确传输信息
明确数据的组合格式
常见的几种的协议模板
1. xml
比较老牌的数据格式:可读性高,运行效率不行
<标签名>内容<标签名>
xml ,正是因为 它这个繁琐格式
,导致它的热度逐渐就降低了。 因此,xml 现在很少作为 应用层协议的设计模板了。 现在使用 xml,主要是作为一些配置文件。
2. json
json 是当下最流行的一种 设计应用层协议 的数据格式
以后在工作中是会经常用到这个
3. Protobuffer
可读性不好,运行效率高
为了解决 json 的问题,Protobuffer 也就是应运而生。 Protobuffer 是一种二进制格式的数据。
在 Protobuffer 的 数据中,不再像 json 那样 包含 key 的 名字了,而是通过顺序以及一些特殊符号,来区分每个字段的含义。 同时再通过一个 IDL文件,来描述这个数据格式(每个部分是什么意思),IDL 只是起到一个辅助开发的效果,并不会真正的进行传输。 传输的只是二进制的纯粹的数据。
小结:
这里面 json 的 应用范围 要比 Protobuffer 更广
通常 开发效率 重于 运行效率的。 开发效率 包含 开发 与 调试。 如果线上环境出问题。 如果使用 json,出问题的请求和响应,一目了然。 如果使用 protobuffer,二进制数据,肯定是没有办法用眼去排查问题的。 为了解决这个问题,只有一个办法:为它专门写一个调试代码,用它去调试,这就更麻烦一些。 这就是我们所说的开发效率上的差异。
二、传输层
传输层和网络层是
操作系统内核实现好的
,,程序员不需要直接和传输层打交道,但是传输层对我们来说仍然是意义重大的!
核心功能:
完成"端对端"的数据传输
进行网络编程都需要用到 socket
,一旦你调用 socket,代码就进入到传输层的范畴。
如果一切顺利,就还好。
一旦代码出现一些bug。为了解决理解这些bug,传输层的一些知识就是必要的。
传输层的协议,面试也中特别爱考,TCP协议
传输层的协议有很多,其中最常见的就是 UDP 和 TCP 协议 下面,学习 UDP 和 TCP 中的一些具体知识。
1.UDP
UDP协议端格式
分析协议
UDP的特点
无连接
:知道对端的IP和端口号就直接进行传输, 不需要建立连接
不可靠
:没有确认机制, 没有重传机制
; 如果因为网络故障该段无法发到对方, UDP协议层也不 会给应用层返回任何错误信息面向数据报
: 不能够灵活的控制读写数据的次数和数量
面向数据报:
应用层交给UDP多长的报文, UDP原样发送,
既不会拆分, 也不会合并
UDP缓冲区:
UDP没有真正意义上的发送缓冲区. 调用sendto会
直接交给内核
, 由内核将数据传给网络层协议进行后续的传输动作UDP具有接收缓冲区. 但是这个接收缓冲区
不能保证收到的UDP报的顺序和发送UDP报的顺序一致
; 如果缓冲区满了, 再到达的UDP数据就会被丢弃UDP的socket既能读, 也能写, 这个概念叫做
全双工
UDP使用注意事项:
- 我们注意到, UDP协议首部中有一个16位的最大长度. 也就是说一个**UDP能传输的数据最大长度是64K(包含UDP首部)**。
- 然而64K在当今的互联网环境下, 是一个非常小的数字。
如果我们需要传输的数据超过64K, 就需要在应用层手动的分包, 多次发送, 并在接收端手动拼装
基于UDP的应用层协议
- NFS:网络文件系统
- TFTP:简单文 件传输协议
- DHCP:动态主机配置协议
- BOOTP:启动协议(用于无盘设备启动)
- DNS:域名解析协议
2.TCP ※
TCP全称为 “传输控制协议(Transmission Control Protocol”). 人如其名, 要对数据的传输进行一个详细的控制 TCP是一个非常重要的协议,不光在实际开发中广泛使用,同时也是面试中的高频问题
TCP协议段格式
在真正理解TCP的一些机制之前,这里面的很多信息,以目前的知识储备是无法理解的。
因此,
光看报头结构,还不够
!!! 还得结合TCP这里面的一些具体的工作机制
,进一步理解 TCP是怎么工作
然后,才能去明确 TCP报头,这里面都在做些什么。
TCP的特点
TCP协议的主要机制
① 确认应答(ACK)机制
确认应答:
保证可靠传输的核心机制
,关键就是接收方收到消息之后,给发送方返回一个应答报文(ACK)表示自己收到了
序号和确认序号:
TCP将
每个字节的数据
都进行了编号,即为序号
每一个ACK都带有对应的
确认序号
,意思是告诉发送者,我已经收到了哪些数据,下一次你从哪里开始发
② 超时重传机制
相当于对
确认应答
进行了补充,确认应答是网络一切正常的时候,通过ACK通知发送方我收到了,如果出现了丢包的情况,超时重传机制就会起到效果
出现丢包的两种情况:
第一种::发出去的消息丢了
第二种:另外一种情况就是 ACK 丢了,虽然对方收到了消息,但是我收不到 ACK
TCP内部去重
如果是 ACK 丢了此时触发的超时重传,就会导致对方接收到重复的消息
,TCP内部就会有一个去重操作,
接收方接收到的数据先会放到操作系统内核的"接收缓冲区"中
,接收缓冲区可以视为是一个
内存空间
,并且也可以视为是一个阻塞队列
收到新的数据,TCP就会根据序号,来检查这个数据是不是在接收缓冲区中已经存在了,如果不存在,就直接进去,如果存在直接丢弃
。保证
应用层
序调用socket api 拿到的这个数据一定不是重复
的。
注意:
如果重传失败,可能还会再尝试,也不会无休止的重传,连续几次重传都不行,就认为这个网络可能是遇到了严重的情况,再怎么传都不行就只能放弃了
基于上述:
确认应答和超时重传两个机制,TCP的可靠性,得到了有效的保障
③ ※ 连接管理机制 ※
连接管理也是TCP保证可靠性的一个机制
。在正常情况下, TCP要经过
三次握手建立连接
、四次挥手断开连接
三次握手(建立连接)
三次握手
客户端和服务器之间,通过三次交互,完成了建立连接的过程
。"握手"是一个形象的比喻。
解释:
其实一次握手,就是一次交互的过程。 就是客户端 给 服务器 发了一个数据,这就相当于一次握手。 服务器再给客户端反馈一个数据,这就是另外一次握手。 客户端 根据服务器的反馈,而进行反馈,告诉服务器,它接受到了它的反馈, 一共经历3次,就完成这个三次握手。
图解:
核心:
为什么是三次握手?
中间两次可以合二为一
拓展:
我们第一次看到的那个完整的图是什么意思呢?
三次握手什么用?
三次握手相当于
投石问路
检查当前这个网络的情况是否满足可靠传输的基本条件
让双方协商一些必要信息
-> 更具体的说,可以认为三次握手其实也是在检测通信双方,发送能力和接受能力是否都正常
如果网络不稳定怎么办?
结论:
三次握手
对于 TCP可靠传输
来说,是非常必要
的,尤其是这个“投石问路
”的过程,非常重要!
典型面试题
- 描述 TCP 三次握手的过程。
↑上述画图
- 为什么握手三次?两次行不行?四次行不行?
首先,
4 次是可以的,但是!没必要!
三次握手 本就是一个双向奔赴的过程,本来就是 4次交互。 前面也说到了
中间的那两次是可以合并,没必要分成两次,来降低执行效率
两次,绝对不行的。
如果是两次,
意味着 服务器(乙方),只能确定它大的接收能力是正常的,发送能力是无法确定的
;而客户端(甲方)的接收 和 发送能力都是正常的,
此时,服务器对于进行可靠传输,心里是没底的。 因为它的的发送能力是无法保证的。 故,进行第三次握手,就是为了给服务器吃一个定心丸。 告诉它目前没有任何问题,放心大胆的进行后面的操作。
四次挥手(断开连接)
四次挥手,是为了释放必要的资源。
那么,4次挥手,又是
怎么挥
的呢?虽然它的
目的 和 三次握手 不同
,但是流程非常相似!
三次握手 和 四次挥手 的区别
TCP协议中的状态
小结
TCP 虽然可靠性是最高的机制,但是TCP也会尽可能的提高效率!!
也就是说:除了刚才的可靠性之外,还回在引入其他的机制来提高传输的效率。
④ 滑动窗口机制
滑动窗口存在的意义就是在保证可靠性的前提下,尽量提高传输效率
这样一发一收
的方式性能较低, 那么我们一次发送多条数据
, 就可以大大的提高性能(其实是将多个段 的等待时间重叠在一起了)
更直观的图👇
滑动窗口丢包怎么处理
- ACK 丢了
- 数据丢了
情况一: ACK丢了
这种情况下, 部分ACK丢了并不要紧, 因为可以通过后续的ACK进行确认
情况二: 数据包丢了
这里的重传只是需要把丢了的那一块数据给重传了即可
,其他已经到了的数据就不必再重传了,整体的重传效率还是比较高的(
快重传
)
这个快重传就像看电视剧
注意:
⑤ 流量控制机制
流量控制,是滑动窗口的延伸,目的是为了保证可靠性。
在滑动窗口中,窗口越大(一次传输的数据量),传输速率也就越高。 那么,有些朋友就会这么去想:我把窗口弄得越大越好,这样的我们数据传输量就大幅度提升了。 答案:不行!
把窗口弄大,不光要考虑发送方,还得考虑接收方。
如果发送方发送的速度非常快,接收方完全就处理不过来,接收方就会把新接收到的包给丢了。 那么,发送方是不是还得重传,这就不就在浪费时间和资源嘛!
流量控制的关键,就是要能够衡量接收方的处理速度。
怎么去衡量呢?
我们有一个明确的指标。
此处,我们就直接使用接收方 接收缓冲区 的 剩余空间大小,来衡量当前接收方的处理能力。
问题又来了:怎么使 接送速度 动态平衡
通过ACK报文来告知
,剩余空间多大
⑥ 拥塞控制机制
拥塞控制,也是滑动窗口的延伸,也是用来限制 滑动窗口 发送的速率。
拥塞控制,
衡量的是 发送方到接收方,这整个链路之间,拥堵情况(处理能力)
根据这个情况,我们来
去决定发送的速率是多少
具体这个拥塞窗口是如何变化的:
⑦ 延迟应答机制
相当于流量控制的延伸,流量控制可以理解为刹车
使发送方,发的不要太快,延伸应答,就想在这个基础上,能够尽量的再让窗口更大一些
先画个图方便大家理解:
延时应答,具体延时多少呢?
1、数量限制:每隔N个包就应答一次;
2、时间限制:超过最大延迟时间就应答一次
⑧ 捎带应答机制
捎带应答,又是延时应答的延伸。
在延迟应答的基础上, 我们发现, 很多情况下, 客户端服务器在应用层也是 “一发一收” 的. 意味着客户端给 服务器说了 “How are you”, 服务器也会给客户端回一个 “Fine, thank you”
那么这个时候ACK就可以搭顺风车 , 和服务器回应的 “Fine, thank you” 一起回给客户端
客户端和服务器之间的通信,有以下几种模型:
1.
一问一答
:客户端发一个请求,服务器返回一个对应的响应2.
多问一答
:上传文件3.
一问多答
:下载文件4.
多问多答
:直播~~串流…
面向字节流 => 粘包问题
首先要明确, 粘包问题中的 "包" , 是指的应用层的数据包
TCP粘包指的是粘 的是应用
层数据报
,在 TCP 接收缓冲区中,
若干个 应用层数据包混在一起了,分不出来谁是谁
怎么解决粘包问题?
TCP异常情况
1.进程终止
2.机器关机
3.机器掉电/网线断开
面试题:
如何基于UDP协议实现可靠传输?
这个题其实就是考TCP,本质上就是在应用层基于UDP复刻TCP的机制
实现确认应答机制
. 每个数据收到之后,都要反馈一个ACK(应用程序自己定义一个 ack包)
实现序号/确认序号,以及实现去重
实现超时重传
实现连接管理
要想提高效率,实现
滑动窗口
为了限制滑动窗口,
实现流量控制/拥塞控制
实现
延时应答,捎带应答……
啥样的场景中适合使用TCP,啥样的场景中适合使用UDP
1:啥时候
使用TCP
? =>对可靠性有一定要求
,(日常开发中的大多数情况,都基于TCP)2:如果传输的
单个数据报比较长(超过 64k)
-> 首选TCP
3:啥时候
使用UDP
? =>对可靠性要求不高
,对于效率的要求更高
(机房内部的主机之间通信,分布式系统中,广播就是首选UDP)