0%

Web页面请求过程

CorsiniGardens_ZH-CN8547012221_1920x1080.jpg

模拟局域网中有网线的主机向外网服务器发送 HTTP 请求,获取 dzapathy.github.io 页面

浏览器和服务器是应用层程序,使用 HTTP / HTTPS 协议进行网络通信,HTTP 的底层协议是 TCP 协议。为了能够进行通信,首先需要知道源 IP 地址和目的 IP 地址

源 IP:DHCP

假设主机没有 IP 地址以及相关信息,需要使用 DHCP 协议获取 IP 地址

  • 主机发送 DHCP 发现报文
    • 主机应用层生成 DHCP 发现报文,并向下传送给传输层
    • 主机传输层将 DHCP 发现报文封装成 UDP 报文段,源端口号是 68,目的端口号是 67,并向下传送给网络层
    • 主机网络层将 UDP 报文段封装成 IP 数据报,源 IP 地址是 $0.0.0.0$,目的 IP 地址是 $255.255.255.255$,向下传输给数据链路层
    • 主机数据链路层将 IP 数据报封装成数据帧,源 MAC 地址是主机 MAC 地址,目的 MAC 地址是 $FF:FF:FF:FF:FF:FF$,并发送给物理层
    • 主机物理层以比特流的方式传输数据帧,将数据帧发送到交换机
    • 交换机将主机的 MAC 地址及对应的接口记录在交换表中,然后在交换机的所有出口广播这个数据帧
    • DHCP 服务器(路由器可以作为 DHCP 服务器)收到广播的数据帧,拆开首部和尾部得到 IP 数据报并向上传送给网络层
    • DHCP 网络层拆开 IP 数据报首部得到 UDP 报文段,并将其发送给传输层
    • DHCP 传输层拆开 UDP 数据报得到 DHCP 报文,并将其发送给应用层
    • DHCP 应用层服务器得到 DHCP 发现报文
  • DHCP 服务器发送提供报文
    • DHCP 应用层生成 DHCP 提供报文,包含 IP 地址、子网、网关 IP 和 DNS 服务器 IP 信息,并向下传送给传输层
    • DHCP 传输层将 DHCP 提供报文封装成 UDP 报文段,源端口号是 67,目的端口号是 68,并向下传送给网络层
    • DHCP 网络层将 UDP 报文段封装成 IP 数据报,源 IP 地址是 DHCP 服务器 IP 地址,目的 IP 地址是 $255.255.255.255$,向下传输给数据链路层
    • DHCP 数据链路层将 IP 数据报封装成数据帧,源 MAC 地址是DHCP MAC 地址,目的 MAC 地址是 $FF:FF:FF:FF:FF:FF$,并发送给物理层
    • DHCP 物理层以比特流的方式传输数据帧,将数据帧发送到交换机
    • 交换机将 DHCP 服务器的 MAC 地址及对应的接口记录在交换表中,然后在交换机的所有出口广播这个数据帧
    • 主机收到广播帧,依次经过数据链路层、网络层、传输层、应用层得到 DHCP 提供报文
  • 主机发送 DHCP 请求报文
    • 源端口号是 68,目的端口号是 67,源 IP 地址是 $0.0.0.0$ ,目的 IP 地址是 $255.255.255.255$,依次经过应用层、传输层、网络层、数据链路层和物理层发送给 DHCP 服务器,DHCP 服务器经过数据链路层、网络层、传输层、应用层得到 DHCP 请求报文
  • DHCP 服务器发送 DHCP 确认报文
    • 源端口号是 67,目的端口号是 68,源 IP 地址是 DHCP IP地址,目的 IP 地址是 $255.255.255.255$
    • 主机收到 DHCP 确认报文,得到自己的 IP 地址、子网掩码、DNS 服务器 IP 地址和网关 IP 地址

pic

至此,主机获得 IP!

网关 MAC: ARP

假设主机没有网关路由器的 MAC 地址的 ARP 高速缓存

主机在局域网中,要访问局域网之外的主机需要通过网关路由器来进行访问。由于局域网内的 IP 地址可能比较紧缺,所以使用 DHCP 协议进行动态主机配置。DHCP 是有租期的,也就是说 IP 地址可能会改变,所以在局域网内使用 MAC 地址作为主机的唯一标识。对于主机来说,唯一不变的是 MAC 地址。所以要获取网关服务器的 MAC 地址

  • 主机应用层生成 ARP 查询报文,源 IP 地址是主机 IP 地址,目的 IP 地址是主机的默认网关路由器 IP 地址。经过传输层、网络层、数据链路层和物理层将数据帧发送给交换机
  • 交换机将数据帧广播出去
  • 网关路由器接收到数据帧,层层解析得到 ARP 查询报文,发现 ARP 查询报文的目的 IP 地址与自己某个网络接口 IP 地址匹配,发送 ARP 应答报文,报文中包含网关 MAC 地址

至此,主机能够与默认网关进行通信!

转换 IP: NAT

假设主机 IP 地址是私有 IP 地址

如果在局域网内部使用私有地址就无法与外部网络进行通信。为了保证通信,需要在网关处使用网络地址转换协议 NAT 将私有地址转化为公有地址

  • 在 NAT 路由器转换表中记录 公有IP,新端口号源IP,源端口号 的映射关系,转换方式包括静态转换、动态转换和端口多路复用等
  • 内网向外网发数据:根据 NAT 转换表,利用 公有IP,新端口号 替换每个外出 IP 分组的源IP,源端口号
  • 外网向内网发数据:根据 NAT 转换表,利用源IP,源端口号 替换每个 IP 分组的 公有IP,新端口号

至此,主机能够通过默认网关与外网进行通信!

目的 IP:DNS

假设主机没有 DNS 缓存,并且 DNS 查询使用迭代查询

  • 首先主机将查询发送给本地域名服务器
  • 本地域名服务器无法解析域名时,本地域名服务器作为代理转发查询访问根域名服务器
    • 请求在网络核心通过路由器进行路由转发,由于路由器实现了内部网关协议(RIP,OSPF)和外部网关协议(BGP),所以请求能够正确的到达 DNS 域名服务器
  • 根域名服务器无法解析域名时,返回顶级域名服务器 io
  • 本地域名服务器查询顶级域名解析服务器 io
  • 顶级域名解析服务器无法解析域名时,返回权威域名服务器 github.io
  • 本地域名服务器查询权威域名服务器 github.io
  • 权威域名服务器 github.io 返回 dzapathy.github.io 的 IP 地址
  • 本地域名服务器将 dzapathy.github.io 的 IP 地址返回给客户端

至此,主机获得目的 IP 地址!

建立连接:TCP 三次握手

现在已经获得了源 IP 地址,源端口号,目的 IP 地址和目的端口号,就可以进行 TCP 三次握手了

  • 服务器一直处于 LISTEN(监听)状态,等待客户的连接请求
  • 客户端向服务器发送请求报文,SYN=1,ACK=0,随机初始化序号 x
  • 服务器收到请求报文,如果同意建立连接则向 A 发送连接确认报文,SYN=1,ACK=1,确认号为 x+1,随机初始化序号 y
  • 客户端收到服务器的确认报文后进行第三次握手,确认号为 y+1,序号为 x+1
  • 服务器收到客户端的第三次握手后,连接 TCP 建立

pic

至此,主机和服务器建立了 TCP 连接,能够进行 HTTP 通信!

请求:HTTP

假设服务器使用 SpringMVC

  • 主机发送 HTTP GET 请求报文,经过传输层、网络层、数据链路层和物理层交付给服务器
  • 服务器层层拆分得到 HTTP GET 请求报文
  • 服务器生成 HTTP 响应报文,将页面数据放入报文实体部分并发送给主机
    • SpringMVC 前端控制器接收请求,并将请求发送给处理器映射器
    • 处理器映射器根据 URL 查找处理器,并将处理器返回给前端控制器
    • 前端控制器将处理器发送给处理器适配器,通过处理器适配器访问处理器
    • 执行处理器
    • 处理器会返回一个 ModelAndView 对象给处理器适配器
    • 处理器适配器将 ModelAndView 返回给前端控制器,包括数据和视图
    • 前端控制器向视图解析器发送视图解析请求
    • 视图解析器返回视图对象
    • 前端控制器进行视图渲染,将model转行成responce
  • 浏览器收到 HTTP 响应报文,使用浏览器渲染页面,最后显示页面

pic

至此,主机获得请求页面!

断开连接

HTTP/1.1 之前默认是短连接的,一旦服务器发送完数据就会主动断开 TCP 连接,进行 TCP 四次挥手。HTTP/1.1 默认是长连接,不会立刻断开连接,可以设置 keep-alive 的 timeout,当到 timeout 后仍然没有数据传输就断开连接