从URL到页面显示
从URL到页面显示
1.解析 URL
浏览器第一步要做的就是解析 URL
,从而生成发送给 Web
服务器的请求信息。
URL 元素组成
http: + // Web服务器 + [/ + 目录名 + / ... + 文件名]
对 URL
进行解析之后,浏览器确定了 Web 服务器和文件名,接下来就是对这些信息生成 HTTP 请求。
2. DNS 解析域名
浏览器解析 URL 并生成 HTTP 消息后,需要委托操作系统将消息发送给 Web 服务器。
但是委托操作系统发送消息时,必须提供通信对象的 IP 地址。
而用户输入的服务器域名,如 www.baidu.com
, 并不是真正意义上的地址。互联网上每一台计算机的唯一标识是他的 IP 地址,那么我们就需要通过 DNS 解析域名
,通过服务器域名获得其真实的 IP 地址。
例如,我们可以使用 ping
命令来获取 www.baidu.com
的真实 IP 地址
可以看到 39.156.66.14
才是其服务器的 IP 地址,那么我们就可以直接通过这个地址访问其首页
那么我们的计算机又是如何进行域名到IP地址的转换呢?
有一种服务器专门保存了 Web 服务器域名
与 IP 地址
的对应关系,它就是 DNS 服务器
。
域名层级关系
DNS 中的域名都是用 .
来进行分割的,比如 www.baidu.com
,这里的 .
代表了不同层次之间的界限。
在域名中,从左到右,层级递增。
域名的层级结构类似树状结构:
- 根 DNS 服务器 (
.
) - 顶级域 DNS 服务器 (
.com.
) - 权威 DNS 服务器 (
.baidu.com.
)
这里并不是多打了一个 .
,这个 .
对应的就是根域名服务器,默认情况所有网址的最后一位都是 .
, 则为了方便用户通常都会省略。
域名解析
上图就是查找 www.baidu.com
的 IP 地址过程。
- 客户端发出 DNS 请求,发送给本地域名服务器,查询 www.baidu.com 的 IP 地址
- 本地域名服务器收到客户端请求后,如果缓存中能够找到 www.baidu.com 的 IP 地址,则它直接返回给客户端
- 若没有在缓存中找到则会询问根域名服务器
.com
的地址。 - 根域名服务器不直接解析域名地址,而是保存了顶级域名服务器的地址。 根域名服务收到本地域名服务器的请求后,会返回
.com
顶级域名服务器的 IP 地址。 - 本地域名服务器收到
.com
的 IP 地址后,向顶级域名服务器发出请求。 - 顶级域名服务器收到请求后,返回权威域名服务器
.baidu.com
的 IP 地址 - 本地域名服务器收到权威域名服务器地址后,向权威域名服务器发出请求。
- 权威域名服务器查询对应的 IP 地址
39.156.66.14
返回给本地域名服务器 - 本地域名服务器收到 IP 地址后,会将其保存到高速缓存中
- 本地域名服务器将 IP 地址返回给客户端。
利用 dig +trace xxx.xxx.xxx
命令,我们可看到 DNS 解析
的过程。
3. TCP 连接
HTTP 协议是使用 TCP 作为传输协议的。
TCP 格式
我们首先来看看 TCP 报文头的格式
- 端口号:TCP 位于运输层,运输层提供了进程间的逻辑通信。故需要源端口号和目标端口号,将数据转发给特定的应用。
- 序号:用于对字节流进行编号。在网络中,报文段并不一定是按照发送顺序达到目的地的,因此需要序号来解决乱序的问题。例如序号为 201,表示第一个字节的编号为 201,如果携带的数据长度为 100 字节,那么下一个报文段的序号应为 301。
- 确认号:期望收到下一个报文段的序号。例如 B 正确收到 A 发送来的一个报文段,序号为 501,携带的数据长度为 200 字节,因此 B 期望下一个报文段的序号为 701,B 发送给 A 的确认报文段中确认号就为 701。
- 数据偏移:指的是数据部分距离报文段起始处的偏移量,实际指的首部长度。(TCP 首部的长度并不是固定的)
- 确认 ACK:当 ACK=1 时,确认号字段有效,否则无效。TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 置为 1
- 同步 SYN:在连接建立时用来同步序号。当 SYN=1,ACK=0时表示这是一个连接请求报文段,若对方同意建立连接,则响应报文中SYN=1,ACK=1。
- 终止 FIN:用来释放一个连接,当 FIN=1 时,表示此报文段的发送方数据已发送完毕,并要求释放连接。
- 窗口:TCP要做流量控制,通信双方各申明一个窗口大小,标识自己当前的处理能力。
三次握手
- 开始时,客户端和服务端都处于
CLOSED
状态。服务器打开后监听某一端口,处于LISTEN
状态 - 然后客户端主动发起连接请求报文,SYN=1,ACK=0, 选择一个初始序号 x,之后处于
SYN-SENT
状态 - 服务端收到发起的连接,如果同意建立连接,则向客户端发送连接确认报文,SYN=1,ACK=1,确认号为 x+1,同时也选择一个初始序号 y,之后处于
SYN-RCVD
状态 - 客户端收到服务端连接确认报文后,还要向服务端发出确认,ACK = 1,确认号为 y+1,序号为 x+1,之后处于
ESTABLISHED
状态 - 服务端收到客户端的确认后,连接建立,之后处于
ESTABLISHED
状态
TCP连接为什么要进行三次握手?
目的:保证双方都有发送和接收的能力
发送方 | 接收方 | 状态 | |
---|---|---|---|
第一次握手 | 客户端 | 服务端 | 服务端确认客户端具有发送能力 |
第二次握手 | 服务端 | 客户端 | 客户端可以确认服务端具有接收和发送能力 |
第三次握手 | 客户端 | 服务端 | 服务端确认客户端具有接收能力 |
4. IP
TCP 在执行连接、收发、断开等各阶段操作时,都需要委托 IP 将数据封装成网络包发送给通信对象。
IP 数据报格式
- 版本:有4(IPv4)和6(IPv6)两个值
- 首部长度:占 4 位,因此最大值为 15。值为 1 表示的是 1 个 32 位字的长度,也就是 4 字节。因为固定部分长度为 20 字节,因此该值最小为 5。如果可选字段的长度不是 4 字节的整数倍,就用尾部的填充部分来填充。
- 区分服务:用来获得更好的服务,一般情况下不使用。
- 总长度:首部长度和数据部分长度
- 标识 : 在数据报长度过长从而发生分片的情况下,相同数据报的不同分片具有相同的标识符。
- 片偏移 : 和标识符一起,用于发生分片的情况。片偏移的单位为 8 字节。
- 生存时间:TTL,它的存在是为了防止无法交付的数据报在网络中不断兜圈子。以路由器跳数为单位,当 TTL 为 0 时就丢弃数据报
- 协议:指出携带的数据应该上交给哪个协议进行处理,例如 ICMP、TCP、UDP 等。
- 首部检验和 :因为数据报每经过一个路由器,都要重新计算检验和,因此检验和不包含数据部分可以减少计算的工作量。
- 源地址、目的地址:发送方和接收方的 IP 地址
路由表转发
我们可以使用 route -n
命令查看当前系统的路由表
根据上面的路由表,我们假设 Web 服务器的目的地址为 172.16.205.200
- 假设先和第三个条目的子网掩码(
Genmask
) 进行与运算,得到结果为172.16.0.0
,但是第三个条目的Destination
是172.17.0.0
,两者不一致所以匹配失败 - 再与第二个条目的子网掩码进行与运算,得到结果为
172.16.205.0
, 与第二个条目的Destionation
匹配,所以将使用ens33
网卡的 IP 地址进行转发
第一个条目比较特殊,它的目标地址和子网掩码都是 0.0.0.0
,这表示默认网关,如果其他所有条目都无法匹配,就会自动匹配这一行。Gateway
即路由器的 IP 地址。
地址解析协议 ARP
网络层实现主机与主机之间的通信,而链路层实现具体每段链路之间的通信。在通信过程中,IP 数据报的源地址和目的地址始终不变,而 MAC 地址随着链路的改变而改变。
路由器的端口具有 MAC 地址,因此它就能够作为以太网的发送方和接收方,同时还具有 IP 地址。
当转发包时,首先路由器端口会接收发给自己的以太网包,然后路由表查询转发目标,再由相应的端口作为发送将以太网包发送出去。
每个主机都有一个 ARP 高速缓存,里面有本局域网上的各主机和路由器的 IP 地址到 MAC 地址的映射表。
当缓存中不存在所需 IP 地址的 MAC 地址时,就需要 ARP 协议 进行广播
下一个路由器会将包转发给再下一个路由器,经过层层转发之后,网络包就到达了最终目的地。
5. 服务器与客户端
数据包抵达服务器后,服务器会先扒开数据包的 MAC 头部,查看是否和服务器自己的 MAC 地址符合,符合就将包收起来。
接着继续扒开数据包的 IP 头,发现 IP 地址符合,根据 IP 头中协议项,知道自己上层是 TCP 协议。
于是,扒开 TCP 的头,里面有序列号,需要看一看这个序列包是不是我想要的,如果是就放入缓存中然后返回一个 ACK,如果不是就丢弃。TCP头部里面还有端口号, HTTP 的服务器正在监听这个端口号。
于是,服务器自然就知道是 HTTP 进程想要这个包,于是就将包发给 HTTP 进程。
服务器的 HTTP 进程看到,原来这个请求是要访问一个页面,于是就把这个网页封装在 HTTP 响应报文里。
HTTP 响应报文也需要穿上 TCP、IP、MAC 头部,不过这次是源地址是服务器 IP 地址,目的地址是客户端 IP 地址。
穿好头部衣服后,从网卡出去,交由交换机转发到出城的路由器,路由器就把响应数据包发到了下一个路由器,就这样跳啊跳。
最后跳到了客户端的城门把手的路由器,路由器扒开 IP 头部发现是要找城内的人,于是把包发给了城内的交换机,再由交换机转发到客户端。
客户端收到了服务器的响应数据包后,同样也非常的高兴,客户能拆快递了!
于是,客户端开始扒皮,把收到的数据包的皮扒剩 HTTP 响应报文后,交给浏览器去渲染页面,一份特别的数据包快递,就这样显示出来了!
最后,客户端要离开了,向服务器发起了 TCP 四次挥手,至此双方的连接就断开了。