时隔四年,这个系列鸽了四年,我终于觉得我可以按照自己的思路和想法把这个系列完整的表达出来了。
想起四年前,那时候还是2018年的六月份,那时候我还工作不到两年,那时候我翻译了RFC2616的部分内容,发布在了博客园上,并在翻译不久后想要开始整理并学习HTTP相关的知识内容,那时候我以为我可以了。
但是在第一篇《真正“搞”懂http协议01之背景故事发布》之后,我发现我对整个系列的内容分布完全无从下手。这期间我也发布了很多系列内容(其实就是抄抄书),但是一方面没有花时间去刻意的学习,另外一方面觉得对于HTTP的了解还不足以去写一个系列的博客。
刚好,最近想要有一些变化了,所以开始学习HTTP,并且再加上这些年的工作经验大致对于HTTP有了一定的认识和了解,可以按照自己想要的思路来完成这一系列。
那么本系列的设想大致是这样的。
先聊聊HTTP在互联网络模型中的位置以及有哪些互联网络模型,并且不同的互联网络模型是如何分层的,以及整个互联网络模型的数据流转是什么样的。嗯~也就是本篇的内容。
下一篇会再讲讲HTTP的历史,各阶段的HTTP发展及其核心内容,比如各个版本的HTTP都涵盖了哪些头字段,有哪些变化,随着时间的变迁增加了哪些方法,以及更安全的HTTPS、还有性能更优良的QUIC也就是HTTP3。
以上两篇内容,核心就是HTTP在空间和时间上是怎样流转和发展的,其目的是为了让大家对于HTTP在空间和时间上处于怎样的位置,学习HTTP又不能局限于HTTP。
然后,我会根据HTTP在历史上的发展,按照时间线,以一个前端开发的角度(主要是因为我也没别的角度了)带大家深入的去学习HTTP的各项内容并加以分析。
好啦,叙旧就到此为止,我们正式开始吧。
在第一篇背景故事里,我简单的介绍了互联网络模型,特别简单的那种。让人苦恼的是,互联网络模型并不只是单单一种,历史上的大佬根据不同的场景和阶段所产生的不同的需求都对互联网络模型加以不同的分层。
那么这一小节,我们先来简单的了解下什么是互联网络模型。但是在开始聊模型之前,我们得先了解下什么是网络。
网络,可以说是计算机网络的简称,当然,计算机网络是一个很基础的学科,如果大学是计算机专业的一定学过这些。而我们在工作和生活中最常见的网络就是万维网,也即WWW(World Wide Web),是一个透过互联网访问的,由许多互相链接的超文本组成的信息系统。
除了万维网,还有互联网,局域网,等等等等,而万维网其实是互联网的一个子集。我们在工作和生活中最常用的就是万维网,我们通常所说的上网,也即是上万维网,它是基于HTTP协议的,传输 HTML 等超文本资源的,能力也就被限制在 HTTP 协议之内。
OK,我们基本了解了什么是网络。
但是要了解HTTP处于网络中怎样的位置,我们还得看看互联网络模型是什么样的。诶?你叫做互联网络模型,不是叫做万维网络模型?说明了什么?
额~~~你聊网络模型,怎么聊到TCP/IP了?TCP不是协议?IP不也是协议?嗯~~毛病倒是没有,但是TCP/IP协议族是……额……不太好形容,它是互联网中最为**经典的**、**事实的**通信协议标准。
整个TCP/IP协议栈并不单纯的代表TCP和IP,而是代表完整的网络通信家族,由于它创造性的分层设计,所以也叫做**TCP/IP协议栈**。而TCP和IP则是整个家族中最早通过的标准。这些协议最早发源于美国国防部(缩写为DoD)的ARPA网项目,因此也称作DoD模型(DoD Model)。
我们来看张图,整个DoD模型(下面我都这么叫,因为字少~)是这样的:
嗯~就这么简单,层数是由下往上计算的,分别是链接层、网络层、传输层以及应用层。所以,HTTP在哪一层呢?我相信大家都知道HTTP在应用层。
我们从下到上,依次来简单说下各层负责的内容以及各层都大概涵盖了哪些协议,为啥是大概涵盖呢?额~因为整个TCP/IP协议族太大了,有几十个甚至上百个协议,是不是有点夸张。
先来说说DoD模型的第一层,也就是链接层。负责在以太网、WiFi 这样的底层网络上发送原始数据包,工作在网卡这个层次,使用 MAC 地址来标记网络上的设备,所以有时候也叫 MAC 层。注意,这里你尤其要注意下MAC这个词。稍后我们捋线的时候会用到。
然后就是第二层,也就是网络层。IP协议就在这一层,到了这一层,我们就可以通过IP地址来识别目标主机,进行主机级别的目标识别了。
继续,是第三层,也就是传输层。最为大家所熟知的TCP和UDP就在这一层,负责建立传输通道。
最后,就是我们的重中之重,第四层,也就是应用层,我们的HTTP就在这一层,由于前面几层的基础做的非常好,所以,在这一层除了HTTP协议负责传输超文本以外,还有超多的协议,比如我们稍微熟悉一点的HTTPS、DNS、POP、FTP等等等等,好多好多,我们暂时了解一下就可以了。
OK,DoD我们就先这样。继续,长路漫漫,唯贱作伴。
这个东西,有点孩子没娘说来话长,我尽量长话短说。OSI模型是一种概念模型,也即开放式系统互联模型。由国际标准化组织提出,一个试图使各种计算机在世界范围内互连为网络的标准框架。定义于ISO/IEC 7498-1。
为啥已经有了四层还有个七层呢?只有四层不行么?主要是因为当时除了TCP/IP协议以外,还有很多其它协议,整个互联网很混乱,有一种群雄逐鹿的感觉。所以这个时候国际化标准组织就大吼一声,我是秦始皇,我要一统天下,你们都按照我的标准来。
但是,理想是美好的,可惜我不是秦始皇,所以一统天下的局面并没有按照原本设想的那样,于是秦始皇又不得不说,该模型仅供参考。
至于为什么一统天下的局面没有出现,导致我们现在还要多学一个模型,嗯~其实是因为设备僵化。啥意思呢,就是实际中已经很多网络都按照DoD来用了,而且用的很好,不可能换成你的,代价太大。
那这OSI模型有啥意义呢?又没一统天下,实际上也没咋用,那说它干啥。其实它有一个很重要的意义,对!就是参考。OSI模型补足了DoD模型只有纯软件以外的部分,并且形成了规范和标准,并且准确的规定了各层可以使用数字来编号。
故事说完了,我们来看看OSI这七层都是哪七层吧,虽然仅供参考,我们也得知道知道。
我们看图说话噢,上面花里胡哨的那三层就是多出来的三层,第一层是物理层,第五层是会话层,第六层是表示层。嗯,解释解释。
物理层也就是我们互连网络传输中所使用到的各种物理设备,比如集线器,中继器,网卡啥的这些。
会话层呢,负责在数据传输中设置和维护计算机网络中两台计算机之间的通信连接。说人话就是会话层负责在维护网络中的连接状态,也就是保持会话和同步。比如视频的图片和声音的同步。
表示层则会把数据转换成双方都可以理解的可以兼容的格式。
DoD模型和OSI模型的对比,则是这样的:
很好理解,我就不多说了。
现在,我们大致了解了互联网络模型是什么样的,接下来,我们来实际的看一看,一个数据包到底是如何在这些模型中穿梭的。
一种思路是从最底层也就是物理层说起,层层向上递进,这是从最小化网络的场景来聊互联网络协议。另外一种方式就是从应用层,层层向下,这种角度就是以最小数据包的场景,我们下面就采用这种视角来窥一窥一个数据包在网络中的流转。
应用层是离我们最近的一层,这一层往往由安装在系统上的应用程序来处理,这一层的协议有好多好多,也是在整个互联网模型中所拥有最多协议的一层。
应用层协议包括我们所熟悉的HTTP、HTTPS、HTTP2、QUIC等,以及DNS、HTTPDNS、SSH,还有还有比如:
等等,当然还有很多很多。
其中有一部分我们会在本系列中粗略的讲讲,比如DNS、SSH啥的,剩下的与HTTP关联性不大的,大家有兴趣可以自行了解。
在应用层的阶段,我们讲HTTP嘛,所以就以HTTP为例,会形成一个数据包,这个数据包有哪些内容我们暂时可以不去管。反正就是一个包。
当应用层准备好了这个包以后,会把它发往**目标地址**。那么第一个问题来了,当我在应用层准备好数据包之后,我是直接发送么?还是要做什么准备工作?
首先,在准备发起真正的HTTP数据包传递之前,浏览器会率先把目标地址也就是一个域名发送给DNS服务器,换取目标IP。
然后我们就需要进行下一步,创建TCP通道,也就是通过三次握手建立TCP链接。
欸?感觉上面的描述有点问题,我在准备好包以后再去查DNS、建立TCP链接,那如果我TCP链接建立失败了,那我HTTP的数据包不是白处理了么?
哇^v^,好吧,被你发现了,其实这么说确实不太准确,更准确的应该是,在准备发起HTTP请求时,就会去做准备工作,等准备工作都做好了,才会去构建请求信息,然后传递出去。
整个过程,大致如下图所示:
上一小小节,我们停在了与服务器建立链接的部分,这链接还没建立完呢,你就不说话了。嗯。。。因为后面的事情其实与应用层的关系不大,所以我们拿到这一小节传输层来聊一聊。
传输层的协议数量就要比引用层少的多的多的,有点绕,哈哈哈。
传输层协议除了我们最熟悉的TCP与UDP之外,还有诸如:DCCP(数据拥塞控制协议)、SCTP(流控制传输协议)、RSVP(资源预留协议)等协议。当然这些协议,我们了解下就好。重点还是在TCP和UDP。
TCP大名叫做传输控制协议,英文名叫做Transmission Control Protocol,TCP是传输控制协议的英文名的缩写。它是一种面向连接的、可靠的、基于字节流的传输层通信协议。
可靠和基于字节流都比较好理解,面向连接是怎么个意思?我听说过面向对象,面向过程,怎么还有面向连接?怎么个面向法?我在大马路上看车来车往算是面向连接么?(不好意思,一不小心点了一下题)。
假如你在大马路上看车跑来跑去,那如果这个车到了某个目的地又返回到出发点,来来回回,来来回回,那就算是面向连接,如果这车从你面前过去,不回来了,跑没影了,那就不算。
好啦,通过一个小栗子,我们大概理解了什么是面向连接,简单说就是有来有回呗。那么有来无回呢?巧了,就是UDP协议。
UDP的全称是用户数据报协议,英文名叫做**U**ser **D**atagram **P**rotocol,它是一个简单的面向数据包的协议,换句话说,就是我只负责传输数据包,在传输的过程中跑丢了,那就不归我管了。
简单介绍了点概念哈,我们继续上一小节中的图,在真正发送HTTP数据包之前,最重要的就是要创建TCP连接,但是,要注意,我们创建TCP连接时,实际上并不关应用层什么事,只是应用层需要这个连接,所以才告知TCP去建立传输的通道。也就是说,没有应用层咯?嗯,**简单说就是,网络传输中,可以有下层,没上层,但是不可能有上层,没下层。** 这个一定要注意。
那么创建通道的第一步,大家一定耳熟能详,就是TCP的三次握手。欸?为啥是三次,不是一次,不是三十次?嗯,因为三次,是双方可以最小确认彼此的次数。再解释下,也就是说,是客户端与服务器各自都可以收到一个来回的信息,还记得面向连接不?
我们来看看三次握手是咋握的。
欸?你这不对啊,你这哪有握手的过程,"与服务器建立连接"这几个字,就代表了三次握手的内容。当然,真正的三次握手是这样的:
我们来看上图哈,里面还有点东西的。在最开始的时候,客户端和服务器都处于关闭的状态,然后服务器会处于监听的状态。当客户端发起第一次握手连接请求时,客户端会设置当前的状态为SYN_SEND的状态,注意这里发送的seq=x,**这个x并不是一个随机数,而是当前的TCP包的序号**,注意这一点,我们描述完整个过程会在说说这个序号。
服务器收到这个消息后,就会把x+1作为ack结果,也就是返回的消息,在返回的消息中还给回客户端一个seq为y,同样的,这个y也是一个序号。那么此时服务器就处于SYN_RCVD也就是接收到了消息的状态。
继续,当客户端收到了服务器的回信后,知道这个连接已经通知服务器建立了,于是客户端把服务器端传过来的seq再加1作为ack应答给服务器,并且设置当前状态为ESTABLISHED,也就是建交成功,当服务器收到结果,一计算seq和ack没问题,那么服务器也设置为建交成功,可以传递数据了。
这就是三次握手。那为啥要有seq和ack呢?我直接喊一声,你答应一声,然后我再喊一声不就完事了么,非要加一加一干啥啊。
嗯~这是为了记录当前的包是从哪开始的,你想像一下,在马路上跑的车有很多,有的车可能跑丢了,或者跑到别的国家了,压根不回来了,你咋整?所以TCP每发一个包都会记录一下,也就是递增1,你的seq和ack是要属于本次请求要求递增的包序号才算是属于本次建交的应答和响应。
那么接下来就要开始传输数据了,应用层把HTTP数据包都准备好了,已经迫不及待要出发了,那么到了TCP这一层后,TCP会往这个包里加点东西:
TCP会在应用层的HTTP包的基础上再加上TCP头,这里面包含了源端口号和目标端口号,有了端口号,我们就可以确定目标端口号从而找到目标应用,当信息返回的时候还会用到源端口号,这个我们后面再说。
网络层提供路由和寻址的能力,由于在TCP/IP协议族中,网络层的能力由IP协议来实现,所以又称为网络层又可以叫做IP层。
但是网络层可不仅仅只有IP协议,还有比如ICMP(互联网控制消息协议)、IGMP(互联网组管理协议)、BGP(边界网关协议)、RIP(路由信息协议)、OSPF(开放式最短路径优先协议)、RARP(逆地址解析协议)等等。我们简单了解下就可了。
还是说回IP协议,IP的主要任务其实很简单,就是根据源主机和目的主机的地址来传递数据。当数据包到了三层之后,就会把源主机和目的主机的IP地址再加入到数据包中传给第二层。
而这一层的IP头,形象的比喻一下的话,就像是我们所在小区的楼牌号,有了楼牌号我们就能找到具体的人。在互联网中,有了IP才可以找到具体是哪一台机器。
当然,我们仅仅只知道楼牌号还不行,还得知道是哪个省市区的,北京的某某一小区和南京的某某小区,极大的可能会有同一个楼牌号,这肯定不行。
所以我们就得来到下一层,也就是链路层来解决省市区的问题了。
链路层的主要作用是在局域网中专职处理介质的争用与冲突问题。换句话说,就是我到了这个小区,要把快递给谁的问题。而链路层的协议其实也不少,其中还有不少大家耳熟能详的协议,比如GPRS,Wi-Fi都是链路层协议,当然还有很多,有兴趣大家可以自行了解。
链路层也可以叫做MAC层,MAC的全称叫做Medium Access Control,媒体访问控制,它要控制啥呢?其实就是控制数据发送的顺序和目标,谁先发,谁后发,谁来接收谁来发送的问题,不能搞乱了。
当数据传递到MAC层后,MAC层会再加上一个MAC头,这里有源MAC地址和目标MAC地址:
按理来说啊,到这后面就是一片坦途的到达目标服务器了,但是数据包的旅程其实才刚刚开始。
当数据包出了网关之后,也就是出了我们的小区,你的小区会告诉这个数据包下一个小区要去哪,一个小区一个小区的跳啊跳,最终才会到达我们的目的地,那你可能会问,我直接让我的小区告诉我直接要到哪个小区不行么,为啥只能一个一个的跳来跳去的呢,嗯……因为全世界的小区数量太大,你的小区记不了那么多。
到了物理层,实际上就脱离了软件层面,是实实在在的可以接触到的电子设备了,比如光纤,同轴电缆,双绞线等等,嗯……它们是干啥的我都不知道,我也不告诉你。
到了物理层后,数据最终会到达服务器,然后再反过来经历刚才的阶段,层层解开数据包,获取当前层所需要的信息,最终定位到目标应用的端口号,此时,我们包的旅程才算是真正的完成了。
这张图并不完全,明显缺失了很大一块,但是我相信你一定知道那缺失的部分有哪些内容,也当作是留给你的作业吧~
其实到这里本篇就算是完事了,但是完事的有点突然,其实在描述上面的整个数据包流转的过程中,越到底层我描述的就越少,其实我刻意省略了很多关于TCP、IP以及MAC的重要内容,但是这篇系列毕竟不是讲互联网络的,大家知道它在空间上经历了哪些部分即可,如果有兴趣,大家可以自行查找资料学习,我猜你不会找,哈哈哈哈
数据传输完了之后,TCP还需要做一点事情,就是通道建立了,但是当我不需要的时候,我想把通道关闭,不然一直监听着有没有消息给我实在是太累了。
当TCP关闭通道的时候,需要通过四次挥手来确认,它是这样挥手的:
我们解释完这张图,本章就完事啦。
我们简单解释下这张图,当客户端发送一个“我不玩了”的消息后,就会进入到FIN_WAIT_1的状态,等待后续的服务器反馈,当服务器收到消息后,就会在之前的基础上给包序号加+1返回给客户端,那么此时服务器就进入到了CLOSED_WAIT的待关闭状态。
我们稍微跑题一下,在学习了三次握手,和上面四次挥手的图示后,你发现一个问题没有,就是所有的应答都是在请求的基础包序号上+1。换种理解方式就是+1的序号都是作为应答出现的包。
我们继续上面的话题,当客户端收到了服务器的第一次响应应答后,会进入到FIN_WAIT_2的状态,为啥这里客户端要等服务器再发送一个包呢?假如服务器还有未处理完的数据要给你咋整?你不是还得接收,所以要等服务器的数据都处理完毕了,告诉客户端,我这边也可以不玩了才行。
于是,当服务器也结束了自己的任务的时候,就把包发给客户端,客户端进入TIME_WAIT的状态。当服务器收到第二次客户端的应答后,就直接关闭了。
最后,TCP还要求客户端还是要持续的监听一段时间,这个时间就是报文最大生存时间,等了一段时间后,就进入关闭的状态了。
我们看哈,其实整个四次挥手,一次是由客户端发起,一次服务器应答,一次是由服务器发起,客户端应答,最后,客户端再等待一段时间。才最终结束整个挥手过程。
那他为什么不可以像三次握手那样,请求,响应,响应响应,三个步骤就可以了呢。这里有一个核心就是,建立连接时,双方都处于空闲状态,没有正在运行的程序,而关闭时,需要确定双方的程序都结束才可以。所以再四次挥手的由服务器发起的请求的过程中,就是为了等待服务器的任务跑完。
我们稍微回顾下我们本章都学习了什么。
由于篇幅所限,文章很多内容并未详细涉及,因为其实本章所讲内容如果扩大一点,就可以叫做《网络基础》,嗯,可以写好几本书。如果你对此有兴趣并且有时间,我还是十分建议去深入学习一下的。
最后,本人能力有限,若在阅读过程中发现谬误,还望不吝指教。非常感谢~~