一个HTTP请求的全过程

要实现一个 HTTP 请求,大致可以分为三个阶段。首先客户端要连接网络,获取自己的 IP 地址;然后客户端通过 DNS 域名解析得到目标域名的 IP 地址;最后客户端和服务端建立一个 TCP 连接进行网络通信。

一、客户端连接网络,获取一个 IP 地址

要访问 HTTP 服务器,首先客户端需要连接网络。获取到一个 IP 地址的过程如下:

  • 广播一个 DHCP 请求报文,报文封装成 UDP 报文段,设置源端口和目标端口。进而封装成 IP 数据报,目标 IP 地址为 255.255.255.255,源地址 IP 地址为 0.0.0.0。
  • IP 数据报封装成 以太网帧,目标 MAC 地址为 FF:FF:FF:FF:FF:FF。
  • DHCP 服务器在路由器中。路由器接收到 DHCP 请求。路由器可以分配的地址的 CIDR block 68.85.2.0/24。DHCP 服务器分配地址 68.85.2.101 给客户端。DHCP 服务器创建一个 DHCP ACK 报文,包含分配的 IP 地址,DNS 服务器 IP 地址 68.87.71.226,默认网关路由器IP地址 68.85.2.1,子网掩码 68.85.2.0/24。DHCP ACK 报文封装为 UDP 报文,进而封装为 IP 数据报,最后封装为 以太网帧,源 MAC 地址为路由器的 MAC 地址,目标 MAC 地址为客户端 MAC 地址。
  • 客户端收到 DHCP ACK 报文,获取到自己的IP地址和其它地址。

二、域名解析

浏览器输入要访问的 URL。浏览器创建一个 TCP Socket 来发送 HTTP 请求。为了创建 Socket 需要知道目标域名的 IP 地址。因此需要进行 DNS 解析。

  • 创建一个 DNS query 报文。封装为 UDP 报文段。设置目标端口。封装为 IP 数据报目标地址为域名服务器的 IP 地址(通过之前 DHCP 获取的)。
  • 客户端以太网帧需要知道目标地址的 MAC 地址。通过 ARP 协议获取到网关路由器的 MAC 地址。
  • 客户端创建 ARP query 报文。目标IP 地址为默认网关 IP 地址。ARP 报文封装为以太网帧,通过广播报文到达路由器。
  • 路由器接收到 ARP query 报文,响应请求,发送 ARP replay 报文。包含路由器的 MAC 地址。
  • 客户端收到 路由器的 MAC 地址,将 DNS query 报文发送给路由器。DNS query 报文封装为 IP 报文,目标 IP 地址是 DNS 服务器,最后封装为链路层报文目标地址是路由器的 MAC 地址。
  • 路由器收到 DNS query 报文,根据转发表将报文转发到下一跳路由器。
  • 经过 ISP 内路由协议和 ISP 之间的路由协议,最终 IP 报文到达 DNS 服务器。DNS 服务器查询缓存得到目标域名的 IP 地址,响应请求,发送 DNS reply 报文。
  • 客户端通过 DNS reply 报文得到目标域名的 IP 地址。

三、通过 HTTP 和 TCP 请求服务器

客户端创建 TCP Socket,发送 HTTP GET 报文给服务器。首先需要 TCP 三次握手。

  • 客户但创建一个 TCP SYN 报文段,目标端口为 80。TCP 报文封装为 IP 报文,目标地址为服务器 IP 地址。最后封装为链路层报文,目标 MAC 地址为网关路由器 MAC 地址。
  • 路由器转发包含 TCP SYN 的 IP 报文给服务器。经过 ISP 内路由协议和 ISP 之间的路由协议,最终 IP 报文到达服务器。
  • 服务器响应一个 TCP SYNACK 报文。
  • 客户端收到 TCP SYNACK 报文,发送应答报文。TCP 连接成功建立。
  • 客户端浏览器创建 HTTP GET 报文,将 HTTP 报文写入 Socket 中,HTTP GET 报文作为 TCP 报文段的负载,进而封装为 IP 报文,经过路由转发请求报文发送到服务器。
  • 服务器通过 Socket 收到 HTTP GET 请求报文,然后创建一个 HTTP response 报文,把网页内容放到 HTTP 响应报文的 body 中。把报文发送给 Socket。通过报文封装和路由转发,响应报文发送到客户端。
  • 客户端通过 Socket 收到收到 HTTP 响应报文,提取 HTTP 响应报文 body,显示网页。