大概的一个执行流程:
执行操作的一个步骤?(大概是这么叫吧)
①解析URL
②解析之后将http消息发给DNS
③通过DNS获取IP
④进行TCP连接
⑤IP进行远程定位,将数据封装成网络包发送给通信对象
⑥
一,解析URL
首先先对url的组成进行一个初步了解:
eg:
如果我键入www.bilibili.com/video/BV****, 访问的就是哔哩哔哩服务器下video目录下BV号为多少多少的一个网页;
如果我键入www.bilibili.com (后面没有任何信息了),那就是访问的默认的/index.html 或者 /default.html(即服务器事先设置好的默认文件)
对URL进行解析之后,浏览器确定了 Web 服务器和文件名,接下来会根据这些信息来生成HTTP请求信息:
注意,此时这么一个HTTP数据包发送到浩瀚的网络中,“无亲无友,不知道谁能保护它,也不清楚自己的目的地在何处”,因此需要一个东西去引导他指向要到达的地址,即
二,真实地址查询--DNS
DNS服务器专门存的是一个 Web 服务器域名跟 IP 的对应关系。
在发送之前,还有一项工作需要完成,那就是查询服务器域名对于的 IP 地址,因为委托操作系统发送消息时,必须提供通信对象的 IP 地址。
比如我们打电话的时候,必须要知道对方的电话号码,但由于电话号码难以记忆,所以通常我们会将对方电话号 + 姓名保存在通讯录里。
正入我们现实中的住址一样,如**省**市**区***街道***号一样,DNS中的域名也存在着这样一个层级结构,DNS 中的域名都是用句点来分隔的,比如 www.bilibili.com
,这里的句点代表了不同层次之间的界限。
在域名中,越靠右的位置表示其层级越高。(跟我们国人习惯相反,毕竟域名这个概念是外国人引进的嘛~~~)
根域在最底层,它的下一层是顶级域com,在下面是bilibili.com。
所以,域名的层级结构是一个树状结构:
根DNS服务器
顶级域DNS服务器(com)
权威DNS服务器(bilibili.com)
根域的DNS服务器信息保存在互联网中所有的DNS服务器中。如此一来,任何DNS服务器都可以找到并访问根域的DNS服务器中。
域名解析的工作流程:
大致如图所示:
-
客户端首先会发出一个 DNS 请求,问 www.server.com 的 IP 是啥,并发给本地 DNS 服务器(也就是客户端的 TCP/IP 设置中填写的 DNS 服务器地址)。
-
本地域名服务器收到客户端的请求后,如果缓存里的表格能找到 www.server.com,则它直接返回 IP 地址。如果没有,本地 DNS 会去问它的根域名服务器:“老大, 能告诉我 www.server.com 的 IP 地址吗?” 根域名服务器是最高层次的,它不直接用于域名解析,但能指明一条道路。
-
根 DNS 收到来自本地 DNS 的请求后,发现后置是 .com,说:“www.server.com 这个域名归 .com 区域管理”,我给你 .com 顶级域名服务器地址给你,你去问问它吧。”
-
本地 DNS 收到顶级域名服务器的地址后,发起请求问“老二, 你能告诉我 www.server.com 的 IP 地址吗?”
-
顶级域名服务器说:“我给你负责 www.server.com 区域的权威 DNS 服务器的地址,你去问它应该能问到”。
-
本地 DNS 于是转向问权威 DNS 服务器:“老三,www.server.com对应的IP是啥呀?” server.com 的权威 DNS 服务器,它是域名解析结果的原出处。为啥叫权威呢?就是我的域名我做主。
-
权威 DNS 服务器查询后将对应的 IP 地址 X.X.X.X 告诉本地 DNS。
-
本地 DNS 再将 IP 地址返回客户端,客户端和目标建立连接。
至此,我们完成了 DNS 的解析过程。
整个过程就和我们日常生活中找人问路的过程类似,只指路不带路。
那么,一个数据包在知道了目的地的情况下,要发出去,又该需要谁的帮助呢?
三,指南好帮手--协议栈
我们通过DNS 获取到IP之后,就可以把HTTP的传输工作交给操作系统中的协议栈了,
协议栈的内部有几个不同的组成,分别承担不同的工作。上下关系是有一定的规则,跟我们现在的领导差球不多,上级向下级委托工作,下级收到委托工作并执行。
应用程序(浏览器)通过调用 Socket 库,来委托协议栈工作。协议栈的上半部分有两块,分别是负责收发数据的 TCP 和 UDP 协议,它们两会接受应用层的委托执行收发数据的操作。
协议栈的下面一半是用 IP 协议控制网络包收发操作,在互联网上传数据时,数据刽被切分成一块块的网络包,而将网络包发送给对方的操作就是由 IP 负责的。
此外 IP 中还包括 ICMP
协议和 ARP
协议。
-
ICMP
用于告知网络包传送过程中产生的错误以及各种控制信息。 -
ARP
用于根据 IP 地址查询相应的以太网 MAC 地址。
IP 下面的网卡驱动程序负责控制网卡硬件,而最下面的网卡则负责完成实际的收发操作,也就是对网线中的信号执行发送和接收操作。
数据包看了这份指南表示:“原来我需要那么多大佬的协助啊,那我先去找找 TCP 大佬!”
四,可靠传输--TCP
HTTP 是基于 TCP 协议传输的,那么何为TCP协议呢?
TCP包头格式:
首先,源端口号和目标端口号是不可少的,如果没有这两个端口号,数据就不知道应该发给哪个应用。
接下来有包的序号,这个是为了解决包乱序的问题。
还有应该有的是确认号,目的是确认发出去对方是否有收到。如果没有收到就应该重新发送,直到送达,这个是为了解决不丢包的问题。
接下来还有一些状态位。例如 SYN
是发起一个连接,ACK
是回复,RST
是重新连接,FIN
是结束连接等。TCP 是面向连接的,因而双方要维护连接的状态,这些带状态位的包的发送,会引起双方的状态变更。
还有一个重要的就是窗口大小。TCP 要做流量控制,通信双方各声明一个窗口(缓存大小),标识自己当前能够的处理能力,别发送的太快,撑死我,也别发的太慢,饿死我。
除了做流量控制以外,TCP还会做拥塞控制,对于真正的通路堵车不堵车,它无能为力,唯一能做的就是控制自己,也即控制发送的速度。不能改变世界,就改变自己嘛。
TCP 传输数据之前,要先三次握手建立连接
在 HTTP 传输数据之前,首先需要 TCP 建立连接,TCP 连接的建立,通常称为三次握手。
这个所谓的「连接」,只是双方计算机里维护一个状态机,在连接建立的过程中,双方的状态变化时序图就像这样。
TCP三次握手:
三次握手大致执行流程:
-
一开始,客户端和服务端都处于
CLOSED
状态。先是服务端主动监听某个端口,处于LISTEN
状态。 -
然后客户端主动发起连接
SYN
,之后处于SYN-SENT
状态。 -
服务端收到发起的连接,返回
SYN
,并且ACK
客户端的SYN
,之后处于SYN-RCVD
状态。 -
客户端收到服务端发送的
SYN
和ACK
之后,发送ACK
的ACK
,之后处于ESTABLISHED
状态,因为它一发一收成功了。 -
服务端收到
ACK
的ACK
之后,处于ESTABLISHED
状态,因为它也一发一收了。
所以三次握手目的是保证双方都有发送和接收的能力。
TCP报文生成
TCP 协议里面会有两个端口,一个是浏览器监听的端口(通常是随机生成的),一个是 Web 服务器监听的端口(HTTP 默认端口号是 80
, HTTPS 默认端口号是 443
)。
在双方建立了连接后,TCP 报文中的数据部分就是存放 HTTP 头部 + 数据,组装好 TCP 报文之后,就需交给下面的网络层处理。
至此,网络包的报文如下图。
此时,遇上了 TCP 的 数据包激动表示:“太好了,碰到了可靠传输的 TCP 传输,它给我加上 TCP 头部,我不在孤单了,安全感十足啊!有大佬可以保护我的可靠送达!但我应该往哪走呢?”
五,远程定位(目的地)--IP
TCP 模块在执行连接、收发、断开等各阶段操作时,都需要委托 IP 模块将数据封装成网络包发送给通信对象。
IP包头格式:
在 IP 协议里面需要有源地址 IP 和 目标地址 IP:
-
源地址IP,即是客户端输出的 IP 地址;
-
目标地址,即通过 DNS 域名解析得到的 Web 服务器 IP。
因为 HTTP 是经过 TCP 传输的,所以在 IP 包头的协议号,要填写为 06
(十六进制),表示协议为 TCP。
在 IP 协议里面需要有源地址 IP 和 目标地址 IP:
-
源地址IP,即是客户端输出的 IP 地址;
-
目标地址,即通过 DNS 域名解析得到的 Web 服务器 IP。
因为 HTTP 是经过 TCP 传输的,所以在 IP 包头的协议号,要填写为 06
(十六进制),表示协议为 TCP。
假设客户端有多个网卡,就会有多个 IP 地址,那 IP 头部的源地址应该选择哪个 IP 呢?
当存在多个网卡时,在填写源地址 IP 时,就需要判断到底应该填写哪个地址。这个判断相当于在多块网卡中判断应该使用哪个一块网卡来发送包。
这个时候就需要根据路由表规则,来判断哪一个网卡作为源地址 IP。
在 Linux 操作系统,我们可以使用 route -n
命令查看当前系统的路由表。
举个例子,根据上面的路由表,我们假设 Web 服务器的目标地址是 192.168.10.200
。
路由规则判断:
-
首先先和第一条条目的子网掩码(
Genmask
)进行 与运算,得到结果为192.168.10.0
,但是第一个条目的Destination
是192.168.3.0
,两者不一致所以匹配失败。 -
再与第二条目的子网掩码进行 与运算,得到的结果为
192.168.10.0
,与第二条目的Destination 192.168.10.0
匹配成功,所以将使用eth1
网卡的 IP 地址作为 IP 包头的源地址。
那么假设 Web 服务器的目标地址是 10.100.20.100
,那么依然依照上面的路由表规则判断,判断后的结果是和第三条目匹配。
第三条目比较特殊,它目标地址和子网掩码都是 0.0.0.0
,这表示默认网关,如果其他所有条目都无法匹配,就会自动匹配这一行。并且后续就把包发给路由器,Gateway
即是路由器的 IP 地址。
IP报文生成:
至此,网络包的报文如下图:
此时,加上了 IP 头部的数据包表示 :“有 IP 大佬给我指路了,感谢 IP 层给我加上了 IP 包头,让我有了远程定位的能力!不会害怕在浩瀚的互联网迷茫了!可是目的地好远啊,我下一站应该去哪呢?”
六,两点传输--MAC
最终生成的一个网络包在IP包前还有个这玩意:
再下面就是IP,TCP,HTTP了
七,出口--网卡
IP 生成的网络包只是存放在内存中的一串二进制数字信息,没有办法直接发送给对方。因此,我们需要将数字信息转换为电信号,才能在网线上传输,也就是说,这才是真正的数据发送过程。
负责执行这一操作的是网卡,要控制网卡还需要靠网卡驱动程序。
网卡驱动从 IP 模块获取到包之后,会将其复制到网卡内的缓存区中,接着会其开头加上报头和起始帧分界符,在末尾加上用于检测错误的帧校验序列。
-
起始帧分界符是一个用来表示包起始位置的标记
-
末尾的
FCS
(帧校验序列)用来检查包传输过程是否有损坏
最后网卡会将包转为电信号,通过网线发送出去。
唉,真是不容易,发一个包,真是历经历经千辛万苦。致此,一个带有许多头部的数据终于踏上寻找目的地的征途了!
(关于交换机与路由器没有写)
最终,相互扒皮--服务器 与 客户端
数据包抵达了服务器,服务器肯定高兴呀,正所谓有朋自远方来,不亦乐乎?
服务器高兴的不得了,于是开始扒数据包的皮!就好像你收到快递,能不兴奋吗?