前言
话不多说,直接进入正题。
步骤
总体分为以下几个步骤:
- 在浏览器输入指定网址,浏览器解析URL
- 浏览器通过DNS进行域名解析,获取IP地址
- 浏览器通过IP和端口号,向目标服务器发起TCP连接请求
- 浏览器在TCP连接上,向服务器发送一个请求报文,请求获取网页的内容
- 服务器处理收到的请求,返回响应报文至浏览器
- 浏览器收到HTTP响应
- 读取页面内容,浏览器渲染,解析html源码
- 断开TCP连接
1. 浏览器解析URL
首先浏览器需要先对 URL 进行解析,对 URL 进⾏解析之后,浏览器确定了 Web 服务器和⽂件名,然后根据这些信息来⽣成 HTTP 请求消息。
URL是什么?
URL(Uniform Resource Locator),统一资源定位符,用于定位互联网上资源,俗称网址。 比如[www.baidu.com/s?cl=3] 遵守以下的语法规则:
- scheme:指定访问资源所使用的协议类型(常见的协议有 http、https、ftp、file,其中最常见的类型是 http,而 https 则是进行加密的网络传输)
- host:表示提供资源的主机名或服务器地址(如www.example.com)
- domain:主机名中的域名部分,用于标识网络中的组织或站点(如example.com)
- port:服务器上用于区分具体服务的端口号(http的默认端口号是80)
- path:服务器中资源所在的目录路径,用来定位资源位置(如/archive/)
- filename:路径中具体资源(通常是文件)的名称(如report.pdf)
- paramter: 携带的参数由?后的内容组成(图中没有绘出,但可自行查看网页上的URL)
所以URL实际上用来请求服务器的文件资源,那么就有个疑问:如果省略定位资源的部分,那应该是请求的什么文件?
当没有路径名时,就代表访问根⽬录下事先设置的默认⽂件,也就是 /index.html 或者 /default.html 这些⽂件,这样就不会发⽣混乱了。
2. 域名解析(DNS)
通过浏览器解析 URL 并⽣成 HTTP 消息后,需要委托操作系统将消息发送给 Web 服务器。但在发送之前,还有⼀项⼯作需要完成,那就是查询服务器域名对应的 IP 地址,因为委托操作系统发送消息时,必须提供通信对象的 IP 地址。
所以,有⼀种服务器就专门保存了 Web 服务器域名与 IP 的对应关系,它就是 DNS 服务器。
域名层级关系
www.baidu.com :DNS的域名使用"."来分隔,越靠右的位置代表着域名的层级越高,实际上域名最后还有一个".",最后一个点代表根域名:[www.baidu.com.]
域名层级类似一个树状结构:
- 根DNS服务器(.)
- 顶级域DNS服务器(.com)
- 权威DNS服务器(baidu.com)
域名解析的工作流程
- 客户端发起 DNS 查询,请求解析域名 [www.baidu.com] 对应的 IP 地址,并将该请求发送至本地 DNS 服务器(即在客户端 TCP/IP 设置中填写的 DNS 服务器)。
- 本地 DNS 服务器接收到请求后,首先在本地缓存中进行查询。若缓存中已存在 [www.server.com] 的解析记录,则直接将对应的 IP 地址返回给客户端;若未命中缓存,则向根域名服务器发起查询请求。
- 根域名服务器收到来自本地 DNS 服务器的查询请求后,根据域名后缀识别出该域名属于 .com 顶级域名,并返回负责 .com 顶级域的顶级域名服务器(TLD Server)的地址。根域名服务器本身不提供具体的域名解析结果,仅用于指引查询路径。
- 本地 DNS 服务器根据根域名服务器返回的信息,向 .com 顶级域名服务器发起查询,请求获取 [www.server.com] 的解析信息。
- 顶级域名服务器接收到请求后,返回负责 server.com 域的权威 DNS 服务器的地址,而不直接提供最终的 IP 地址。
- 本地 DNS 服务器随后向 server.com 的权威 DNS 服务器发起查询请求。权威 DNS 服务器是该域名解析数据的最终来源,负责维护并提供域名与 IP 地址之间的映射关系。
- 权威 DNS 服务器查询其解析记录后,将 www.server.com 对应的 IP 地址返回给本地 DNS 服务器。
- 本地 DNS 服务器将最终获得的 IP 地址返回给客户端,客户端据此与目标服务器建立网络连接。
3. 浏览器通过IP和端口号,向目标服务器发起TCP连接请求
协议栈
应用程序浏览器获得IP和端口号后,通过调用 Socket 库来委托操作系统内核中的 TCP/IP 协议栈 工作。
协议栈的上层由传输层协议组成,主要包括分别负责收发数据的 TCP 和 UDP 协议。
协议栈的下层是 IP 协议控制网络包收发操作,它的作用是将数据拆分成一个个网络包,并将这些网络包发送到网络中的目标主机。
其中 IP 还包括 ICMP 协议和 ARP 协议,ICMP协议用于传递网络错误和控制信息,配合 ARP 协议根据 IP 地址查找对应得网卡 MAC 地址
再往下层的网卡驱动程序负责控制具体的网卡设备,而网卡则负责将数据转换为网络信号,在网络中实际发送和接收数据。
HTTP1.0/HTTP2.0/HTTPs等是基于TCP协议传输的,DNS/视频流/实时通信是基于UDP进行传输
TCP建立连接:三次握手
一开始,客户端和服务器都处于 CLOSED 状态,先是服务器主动监听某个端口,处于 LISTEN 状态。
-
第一次握手(SYN)
客户端向服务端发送一个 SYN 报文段,用于请求建立连接。该报文段中包含客户端生成的初始序列号(ISN),记为seq = x。发送完成后,客户端进入 SYN_SENT 状态,等待服务端响应。 -
第二次握手(SYN + ACK)
服务端收到客户端的 SYN 报文段后,若同意建立连接,则向客户端返回一个 SYN+ACK 报文段。其中,seq = y表示服务端生成的初始序列号,ack = x + 1用于确认已收到客户端的 SYN 请求。此时,服务端进入 SYN_RCVD(SYN_RECV) 状态。 -
第三次握手(ACK)
客户端收到服务端的 SYN+ACK 报文段后,向服务端发送一个 ACK 报文段进行确认,其确认号为ack = y + 1。客户端发送该报文段后进入 ESTABLISHED 状态;服务端在收到该 ACK 报文段后,也进入 ESTABLISHED 状态,TCP 连接正式建立。
为什么要三次握手? 三次握手是为了保证双方都有发送和接受的能力,其核心目的是为了在客户端和服务器之间建立一个可靠的、全双工的通信信道,这需要实现两个主要目标:
- 确认双方的收发能力,并同步初始序列号 (ISN)
- 防止已失效的连接请求被错误地建立
4. 浏览器在TCP连接上,向服务器发送一个请求报文,请求获取网页的内容
TCP 三次握手结束后,开始发送 HTTP 请求报文。
请求报文由请求行(request line)、请求头(header)、请求体三个部分组成,如下图所示:
请求行
请求行包含请求方法、URL、协议版本,在请求报文中只占一行
- 请求方法包含 8 种:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE
- URL 即请求地址,HTTP/1.1中请求行通常不是完整的URL,主机和端口一般放在Host请求头中
- 协议版本即HTTP版本号
GET /index.html?user=tom HTTP/1.1
请求头
请求头包含请求的附加信息,由关键字/值对组成,每行一对,关键字和值用冒号":"分隔
请求体
请求体可以承载多个请求参数的数据,包含回车符、换行符和请求数据,并不是所有请求都具有请求数据
5. 服务器处理收到的请求,返回响应报文至浏览器
HTTP响应报文一般由三大部分组成:状态行、消息头、消息体。
状态行
状态行在响应报文的第一行,用来说明服务器对请求的处理结果,格式是HTTP版本 状态码 原因短语
例如:HTTP/1.1 200 OK
消息头
状态行下面是若干行消息头,每一行都是 头字段名: 值 的形式,用来描述响应数据的属性,比如数据类型、长度、缓存方式等。常见的有 Content-Type(告诉浏览器返回的是什么类型数据)、Content-Length(消息体长度)、Set-Cookie 等。所有消息头结束后必须有一个空行,用来标志“头部结束、正文开始”。
消息体
空行之后的内容就是消息体,也就是服务器真正返回给浏览器的数据。它可以是 HTML 页面、JSON 数据、图片的二进制内容等,具体如何解析完全由 Content-Type 决定。有些响应(如 204 No Content)可能没有消息体。
6. 浏览器收到HTTP响应
7. 读取页面内容,浏览器渲染,解析html源码
8. 断开TCP连接
浏览器在不需要和服务器通信时,可以主动关闭 TCP 连接,或者等待服务器的关闭请求。
四次挥手
TCP 连接的断开需要经过四次报文交换,以确保通信双方的数据都能被正确发送和接收。
-
第一次挥手(FIN)
当客户端(或通信任意一方)决定关闭连接时,会向对方发送一个带有 FIN 标志位的报文段,表示自身已无数据需要继续发送。该报文段包含序列号seq = u。发送完成后,主动关闭连接的一方进入 FIN-WAIT-1 状态。 -
第二次挥手(ACK)
对方收到 FIN 报文段后,立即发送一个 ACK 确认报文段进行响应,其确认号为ack = u + 1,表示已成功接收到关闭请求。此时,对方进入 CLOSE-WAIT 状态,而主动关闭连接的一方在收到该 ACK 后进入 FIN-WAIT-2 状态。此阶段连接处于半关闭状态,即主动关闭方不再发送数据,但被动关闭方仍可继续发送未完成的数据。 -
第三次挥手(FIN)
当被动关闭方确认自身的数据已全部发送完成后,会向对方发送一个 FIN 报文段,表示其也准备关闭连接。该报文段包含序列号seq = y。发送后,被动关闭方进入 LAST-ACK 状态,等待最终确认。 -
第四次挥手(ACK)
主动关闭方收到该 FIN 报文段后,向对方发送一个最终的 ACK 确认报文段,其确认号为ack = y + 1。随后,主动关闭方进入 TIME-WAIT 状态;被动关闭方在收到该 ACK 后立即进入 CLOSED 状态,连接正式关闭。主动关闭方需在 TIME-WAIT 状态下等待 2MSL(最大报文段生存时间) ,以确保对方能够收到最终的确认报文,之后才进入 CLOSED 状态。