HarmonyOS-ArkUI Web控件基础铺垫1-HTTP协议-数据包内容
HarmonyOS-ArkUI Web控件基础铺垫2-DNS解析
本文依然为HarmonyOS ArkWeb学习的铺垫文。ArkWeb展示网页,网页走的是http协议,这套协议的底层用的就是TCP协议。如果绕开这些知识点直接学习ArkWeb,您很可能会错过很多速度提升方面的优化思路。建议先打基础。
TCP协议,名为传输控制协议。它规范了网上所有通信设备,尤其是一个主机与另外一个主机之间的数据往来格式以及传输方式。它属于网络分层架构中的传输层。位置在Http的下一层。因为Http我们要详细了解细节,就绕不开这个TCP协议。
协议的本质
我们首先要解释一下,什么是协议。这是一个互联网行业关键词,从网络各种协议,到媒体数据(图片,视频)各种格式,全都是协议的影子。协议到底是怎么回事?这里抛开这个TCP协议不谈,我们只思考,协议本身的本质是什么!
协议的本质就是,规则。 就像我们的语言,汉语,我们规定某物是苹果, 那么无论用户是ABCD,只要看到了这个物品,就会按照规则得到它是苹果即可! A 和 B 双方只要订好了规则,A按照规则打包数据, B收到数据后按照规则拆封数据,就可以原原本本的还原A最初发来的数据,也能了解其中含义。无接触完成事务的闭环。
扩展-网络分层架构及各层职责
我们首先了解一下网络分层架构以及相关协议吧。我们以TCP/IP四层模型为例:
上图为TCP/IP四层模型的分层,以及各层使用场景和实现时采用的协议,和技术栈。
我们可以看出来,当一个数据传输出去的时候,需要经历四层模型,最终将HTTP等应用层协议转换成硬件(交换机,网卡驱动, 路由器等等硬件)可以识别的数据, 从而使得交换机,路由器可以根据其所在层的协议拆包,知道是否接受本数据,或者是否转发数据, 从而完成 A - B的数据传输。
数据的传输是怎么被这些分层架构实现的?
那么当用户A发送一段HTTP数据到B时, 其数据是被这一道道分层操做了什么?这些协议是怎么起作用的呢?
我们以A用户向B用户发送一段Http协议的内容,途径两个路由器跳转。先忽略各项环节中的细节。(如路由器怎么发现的跳转设备, 数据丢了怎么办, 发送数据过快对方处理不来怎么办),我们看理想情况下数据的变化,和途径各个环节怎么被处理的。
如下图所示:
上图中链路层帧数据以及网络层IP数据报格式
TCP协议
有了上一节的铺垫,我们很容易看得出来,TCP它是属于传输层的一种协议,一种传输层的实现方案,和技术栈,而且通过图中的数据传输细节来看,TCP协议负责的内容,和数据在设备与设备路由之前,并没有强联系, 因为路由规则是网络层和链路层做的,到了TCP这里收到的其实是一个个经由网络层拆包后的TCP段!是围绕这些TCP段信息来处理的。例如从发送者和接收者两个方向来讲:
- 作为发送方,从应用层过来的数据,TCP负责将其拆成TCP段。 如HTTP的数据给拆成TCP协议认可的样式。
- 作为接收方,从网络层来的数据,TCP负责将其按序列合并。并给与上层如Http协议代码来处理最终的数据。
除此之外,我粘贴一下官方对TCP协议的介绍,因为这种正式的描述往往是某些面试八股,但您得记住:
TCP协议全名传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义 [1]。
TCP旨在适应支持多网络应用的分层协议层次结构,互连的计算机通信网络中成对的应用程序进程之间能够依靠TCP提供可靠的通信服务来传输字节流。TCP支持双向数据流,应用程序也可以仅单向发送数据。在主机之间,TCP使用端口号标识应用程序服务并且可以多路传输数据流。
传输层职责
没有传输层的世界有多混乱?
当没有传输层协议的时候,数据照样也能从A传到B。我们依赖网络层的IP数据包再经数据链路层封装层网络帧,发出去,经网络设备转发到B端,B按照反方向解析也可以。但是存在一个比较严重的问题是,这些包有的能到达B有的到不了,如果传送的数据比较大, 那肯定要拆分出很多包。 这确保每个包能到达,就更困难。 还有就是这些包到达了,当如何将这些分散的包重新组装呢?
总之只有网络层和链路层的话,网络传递的数据,会变得很不好用,也很不稳定。传几个字节也许可以,(传的内容少意味着封装的帧少,如果降成一个帧,那我们收到之后,就不用管什么按照顺序拼接恢复的问题了,因为就一个帧。)。但是传多了,这种系统几乎不可用!
下图为数据链路层传递数据传递出现的场景:
混乱的比特流毫无价值,可靠有序的数据传输才有意义。 所以传输层必须存在。 TCP是实现传输层能力的一种方式。
TCP作为传输层的一种实现方案必定也应该完成其应有的职责。传输层的存在,是为了解决网络通讯中存在的两个关键问题。
- 保障可靠性(至少保障数据能用,有价值):网络通讯传输的数据,不保证全部都能传输过去,也不保证每一帧数据都能按照顺序传输过去,如果不做处理,我们的逻辑代码根本不能使用这样的数据。所以网络通信的可靠性,必须要被保障,才能收到能用的数据。
- 保障稳定:数据要平缓的被输送
- 保障正确处理:网络通讯的数据,即使来了,被我们保证了可靠性,也不知道是给哪个进程用的。于是需要一个叫做端口的存在,来确定要给什么进程。传输层需要解决
TCP能力
TCP的能力,当然要满足传输层的基本职责,并拥有自己独特的优势。
- 传输层要求低层来的数据要能用,TCP不仅满足了能用,而且好用,传输来的数据,完完整整,一个不落,很稳定!这个是TCP协议独特的优势。之所以独特,是因为传输层协议的其他的解决方案,如UDP,不保证完完整整的到,但是数据依然能用!
- 采用分段与序列号的机制,保证来的数据可以按顺序来,以使得数据能用。
- 采用确认重传机制,保证传输路程中那些丢了的包,能重新传过来。
- 采用滑动窗口机制,动态调整发送速率
- 拥塞控制,根据网络状况自适应降速
有了能力要求,我们就可以考虑实现这些能力,采取什么方案,了解了采取的方案,才能定义其数据包应该包含什么才能完成这些能力。这是一个完整的需求产生,和解决方案的实现思路。
TCP协议的特点:
- 面向连接:应用程序在使用 TCP 协议之前,必须先建立 TCP 连接。
- 可靠性:TCP 提供可靠交付的服务。通过 TCP 连接传送的数据,无差错、不丢失、不重复,并且按序到达。如果数据包丢失或出现差错,则 TCP 负责重发数据。
- 有序性:TCP 能够把发送的数据划分成一个个数据块,编号后发送,接收方根据编号将这些数据块组装成完整的数据。因此,在接收端可以确保数据块按照发送的顺序进行组装。
- 流量控制:TCP 还提供了流量控制的功能,保证发送方的发送速度不会过快,导致接收方处理不及时,从而导致数据丢失。发送方会根据接收方返回的确认信息,调整自己的发送速度。
- 拥塞控制:TCP 能够根据网络状况调整传输数据的速率,防止出现拥塞。如果网络出现拥塞,TCP 会通过降低发送方的数据传输速率和进行重传等措施来保证数据的可靠传输。
所以接下来,我们从TCP的建联开始, 再讲上述机制的实现原理。 最后来根据这里面所有设计的细节,来分析TCP包的数据,这些包里的数据的设计,一定是可以支持上述所有能力的。
TCP建立连接
何为“连接”?
TCP是一个面向连接的协议,但是何为连接呢?全网大片都是讲怎么连接的,但连接究竟是什么?是网传的“虚连接”? 我认为还不够本质,连接的本质在于对于A和B双方,能找到彼此的唯一的,用正常使用的,能精确到设备和端口号的那个信息。也就是地址。 简而言之,就是双方能拿到能用的地址。以能用的地址为标准,彼此拿到就是建立连接了, 拿不到就是建立连接失败,过期了就是不能用了,不符合能用的标准,连接也就废了。
- 地址: 能通过一定的方式定位到彼此设备,以及设备的进程,甚至是某段物理内存!
- 能用:保证数据过来了能正常处理,即为能用。包括
- 双端有比较顺畅的网络设备的路由链路,探测出最佳路径,使数据传输顺畅。路由的下一跳连起来像个链路。也就是所谓的"虚连接"。至少这条路能找到双方的主机。
- 双端有为传输来的数据处理的逻辑。(过期了,不处理了,则不能用。 服务器崩了,逻辑不存在了,则也不能用)
- 双端有为传输来的数据处理的内存资源。(没开辟资源,也不能用)
连接具象化
我们想象一下,一个端到另外一个端连接之后,具象起来到底是什么样子呢?两个设备之间总不能像上个世纪用网线连起来吧。我们以双方发送三个帧为例,看看一双方发送一个帧经历了什么!很简单,主要是路由设备它干了啥:
如图所示,当一个帧发出去之后,到对端,实际上背后蕴含着,路由设备摸石头过河"蹚出一条路"的流程。这条路不是唯一,有好多种,但是但凡对面收到了数据,则代表这条路我们已经走通了!则代表发送的双方的IP地址,是可达的(只不过缺乏了传输层处理,收到的数据可用性差而已)。 那么这一条条能走通的路,就是真实的具象的连接。
TCP建立连接的过程
根据上述对连接的理解,我们不难猜出,TCP建立连接,也就是一个A与B双方向彼此获取有用的地址的过程。
“地址”何来
其实在TCP的体系里,当刚开始建联的时候,就已经拿到这个地址了。但是不确定这个地址究竟是否“有用”。这个地址怎么得到的,是另外一个技术-DNS解析找到这个IP的!
DNS解析(Domain Name System Resolution)是将人类可读的域名, 如www.baidu.com
转换为计算机可识别的IP--如192.0.2.1 的过程。它是互联网的基础设施之一。
关于DNS的内容详见: HarmonyOS-ArkUI Web控件基础铺垫2-DNS解析-CSDN博客
TCP建连接流程
接下来我们要开始引入三次握手四次挥手了。也就是TCP协议所谓的建连到底干了啥??
最初当然是先跑代码,main方法怎么着也得执行吧哈哈哈。我们还是可以了解下真正的三次握手四次挥手之前程序到底干了啥。 比如您想连一个服务端,总不能不给接收对面响应数据开辟缓冲区吧,那网卡收了数据它也没地方存储,这就没办法给消费程序处理了,这不整个系统报废了。
TCP在建立连接前的关键准备动作
TCP处理,是每种操作系统自带的程序,无论是Windows,Linux, macOS,他们都有对TCP协议栈的实现,其程序执行在操作系统的内核中!
- 传输层: 由操作系统内核中的TCP、UDP实现,用来处理连接管理,可靠性,流量控制等。
- 网络层:处理IP协议,也是操作系统内核实现。
- 链路层: 由网卡驱动实现。
这基本是大部分程序员触碰不到的地方。。。
TCP建连前的准备,也是在内核中执行的。
主要做的事情如下图:
三次握手 机制 的分析
TCP为连接做好准备后,接着就要跟目标IP联系了。但是你单方面联系人家,于是你向对方先发个包试试,看看能不能联系上。可能会出现以下几种情况
- 1 您没有收到包,包括以下原因
- 您发的包折在路上了,可能连网络连接通路都没建立成,也可能是传出去但包内容已经损失了,很多种可能。
- 您发的包,目标IP收到了,给您发了个响应,但是响应包折在路上,或者包内容损失了没法用。
- 2 您收到了一个包
- 这个包不是您刚才发的那个包对应的响应包。 而是一个过时包。
- 这个包正好就是您刚才发的那个包对应响应包!这种包才可以知道对面的目标IP是活跃的,有用的。
对于发送方而言,只有最后一种情况,才算通路跑通,注意此时还只是单方面的,对于发送端而言的跑通。
此时您估计察觉出来一个问题了,即: 如何确保目标IP发来的响应包就是您刚才请求包而触发的呢??即 一一对应问题。
针对这种问题,行业内统一的做法就是生成唯一字串,让对方处理完后把这字串给您带回来,您拿到数据一对比就知道了。记住,这是一个方法论!我们做的就是往A数据包里插入一个随机数,B收到数据的时候,回复响应数据,把这个随机数带回去。A收到一校验即可。
于是有关于确认发送端发送的包,和响应端响应的包是否是一对呼应包的 TCP协议字段便出来了:
- 序列号(简称Seq):便是我们上述解决方案中的随机数。代表传输数据的唯一标识。占32位。
- 确认号(简称ack):对端希望收到的下一个序列号。占32位。通常它就是 (从对端收到包的序列号+1)
- SYN: 是一个大小为1bit的标志位。为1,表示当前的包是一个握手包。
- ACK:是一个大小为1bit的标志位。为1时代表包里的那个"确认号"是有效的。
上述四个字段的协同机制:
AB双方为了这个TCP连接,都需要确认与对方的连接是否互通。只有互通了,才能真正的申请TCP链接所需要的专属资源,这些资源对内存有消耗,不能随便开。所以只有确认互通了才能开!保证不浪费!这些资源如下:
- 连接控制块资源
- TCP专属发送缓冲区
- TCP专属接收缓冲区
- 定时器组
- 内存页与队列等等...
那么对于互通而言什么算是互通呢?即:
- A要确认B是否还能正常使用, 所以A->B, B->A A收到了B的确认,对于A方而言,则B可以用了,这样才能真正的开资源。
- 而对于B呢?尽管是A先过来打的招呼,但是万一这收来的打招呼包是A很早以前发来的,路由出现问题,导致A都放弃了包才来怎么办呢??所以对于B而言, A即使是首先打招呼,也不确定A是活跃的。 所以此时B也要再向A打个招呼,确认A是活跃的,才可以确定A可用,才开自己的TCP资源。
如下图所示:
上图中为了保障A B双方彼此通畅,开始用了四条连接来确认彼此可用,但是后一分析得知,B的第一次响应和第二次向A的确认,两条连接,可以合成一条!于是得出:其实全程只需要三次连接,就能确认彼此好用!
这就是三次握手的由来!
下图为现实中,TCP建连三次握手的周转细节,重点包含两个方面
- 数据周转细节
- ACK, SYN, seq, ack字段,对一一对应包的处理保障。
接下来便是网上普遍存在的三次握手图示,有了以上的流程,我们很容易看得懂这个简化版本,不做多余的解释:
八股--为什么会有三次握手?
这个问题重在问你,为什不两次握手就完事儿了,非得三次。。。。也就是二次握手的弊端。
为什么我称之为八股,因为我不相信开发者会将连接过程实现成两次握手!此问题现实中应该不会出现。不会出现的问题,不需要过载提及!假设您自己设计TCP代码,自己好好捋捋都知道这种双工系统建连,握手仅仅三次就够了,握手少了不确保互通,握手多了也没必要。比如我上文给出的分析过程。这种设计在第一版开发就应如此。。。就跟假设我们就来两次握手, 那客户端如果早就断了,服务端直接就开辟资源就是浪费,这种实现方式一般过不了边缘压测,代码没法上线,早就嘎在摇篮里了😂。 为了规避一方不靠谱断掉情况下开无效资源,我们也得确保双方都好用。 正常思路是四次握手可解双方确认可用的问题,但是可以优化,改为三次。
为什么会有三次握手呢?下文为搬运的答案:
答: 三次握手的目的是为了防止已失效的连接请求突然又传送到了服务端,而产生错误。
假设采用两次握手建立连接,客户端第一次向服务端发送建立连接请求,因为网络延迟的原因,一直没有到达服务器。于是客户端再次向服务端重新发送建立连接请求,这次服务端收到连接请求后,向客户端回复确认,建立连接。但是这时网络延迟恢复,服务端又收到客户端第一次发送的连接请求,服务端认为客户端又发起了一次连接,再次回复确认,又建立了一个连接。 服务端认为有两个连接,客户端认为有一个连接,造成数据状态不一致。
至于为什么不像断开连接一样采用四次握手,因为服务端把确认连接请求和向客户端发送的建立连接请求合并成一次请求,发送给客户端了。
下文预告
下节我们会着重讲解,TCP断掉连接涉及的思考。 如果您能看到这里,那么感谢阅览!下文见!