HTTP访问完整过程
参考资料:参考资料 ,这个写得很好,可以阅读原文。
一、解析URL、DNS解析
输入URL
用户在浏览器中输入URL,例如 http://www.example.com/index.html
。
解析URL
浏览器解析URL,提取以下信息:
- 协议:http
- 域名:www.example.com
- 路径:/index.html
二、DNS解析
域名
域名的层级关系类似一个树状结构:
- 根DNS服务器(.)
- 顶级DNS服务器(.com)
- 权威DNS服务器(server.com)
DNS解析过程
- 查看缓存:
- 浏览器会先看自身有没有对这个域名的缓存,如果有,就直接返回;
- 如果没有,就去问操作系统,操作系统也会去看自己的缓存,如果有,就直接返回;
- 如果没有,再去hosts文件看,也没有,才会去问「本地DNS服务器」。
- 客户端发起DNS请求:客户端(如浏览器)需要访问
www.server.com
,首先会发出一个DNS查询请求,询问www.server.com
对应的IP地址。该请求会被发送到本地DNS服务器(通常由客户端TCP/IP设置中配置的DNS服务器地址指定)。 - 本地DNS服务器检查缓存:本地DNS服务器收到请求后,首先检查自身的缓存记录。如果缓存中存在
www.server.com
的IP地址,则直接将该IP地址返回给客户端,解析过程结束。如果缓存中没有记录,则本地DNS服务器会继续向更高层次的DNS服务器发起查询。 - 本地DNS服务器查询根域名服务器:本地DNS服务器向根域名服务器发起查询,询问
www.server.com
的IP地址。根域名服务器是DNS解析体系的最高层次,它并不直接解析域名,但可以提供下一步查询的指引。根域名服务器根据域名的后缀(如.com)判断该域名由哪个顶级域名服务器管理,并将该顶级域名服务器的地址返回给本地DNS服务器。 - 本地DNS服务器查询顶级域名服务器:本地DNS服务器根据根域名服务器返回的地址,向顶级域名服务器(如.com域名服务器)发起查询,询问
www.server.com
的IP地址。顶级域名服务器根据域名的下一级(如server.com)判断该域名由哪个权威域名服务器管理,并将该权威域名服务器的地址返回给本地DNS服务器。 - 本地DNS服务器查询权威域名服务器:本地DNS服务器根据顶级域名服务器返回的地址,向权威域名服务器发起查询,询问
www.server.com
的IP地址。权威域名服务器是域名解析的最终来源,它负责管理特定域名的解析记录。权威域名服务器查询自身的记录后,将www.server.com
对应的IP地址(如X.X.X.X)返回给本地DNS服务器。 - 本地DNS服务器返回结果给客户端:本地DNS服务器收到权威域名服务器返回的IP地址后,将该IP地址缓存到本地,并将结果返回给客户端。
- 客户端与目标服务器建立连接:客户端收到
www.server.com
的IP地址后,使用该IP地址与目标服务器建立连接(如TCP连接),并开始后续的通信(如发送HTTP请求)。
三、协议栈
通过DNS获取到IP后,就可以把HTTP的传输工作交给操作系统中的协议栈。
协议栈的内部分为几个部分,分别承担不同的工作。上下关系是有一定的规则的,上面的部分会向下面的部分委托工作,下面的部分收到委托的工作并执行。
应用程序(浏览器)通过调用Socket库,来委托协议栈工作。
协议栈的上半部分有两块,分别是负责收发数据的TCP和UDP协议,这两个传输协议会接受应用层的委托执行收发数据的操作。
协议栈的下面一半是用IP协议控制网络包收发操作,在互联网上传数据时,数据会被切分成一块块的网络包,而将网络包发送给对方的操作就是由IP负责的。
此外IP中还包括ICMP协议和ARP协议。ICMP用于告知网络包传送过程中产生的错误以及各种控制信息。ARP用于根据IP地址查询相应的以太网MAC地址。
IP下面的网卡驱动程序负责控制网卡硬件,而最下面的网卡则负责完成实际的收发操作,也就是对网线中的信号执行发送和接收操作。
四、传输层:TCP
TCP头部
- 源端口号(Source Port, 16位):标识发送方的端口号,用于区分同一主机上的不同应用程序。
- 目标端口号(Destination Port, 16位):标识接收方的端口号,用于区分目标主机上的不同应用程序。
- 序号(Sequence Number, 32位):标识发送数据的字节流中的第一个字节的序号,用于解决包乱序问题。
- 确认号(Acknowledgment Number, 32位):标识接收方期望收到的下一个字节的序号,用于确认数据是否成功接收。
- 数据偏移(Data Offset, 4位):指示TCP头部的长度(以32位字为单位),用于确定数据部分的起始位置。
- 保留位(Reserved, 3位):保留字段,必须设置为0。
- 控制位(Control Flags, 9位):
- URG(Urgent):紧急指针字段有效。
- ACK(Acknowledgment):确认号字段有效。
- PSH(Push):接收方应立即将数据交给应用层。
- RST(Reset):重置连接。
- SYN(Synchronize):发起连接请求。
- FIN(Finish):结束连接请求。
- 窗口大小(Window Size, 16位):指示接收方当前可接收的数据量(以字节为单位),用于流量控制。
- 校验和(Checksum, 16位):用于检测TCP头部和数据部分的错误,覆盖TCP头部、数据和伪头部(源IP、目标IP、协议类型和TCP长度)。
- 紧急指针(Urgent Pointer, 16位):当URG标志位为1时有效,指示紧急数据的结束位置,用于处理紧急数据。
- 选项(Options, 可变长度):可选字段,用于扩展TCP功能。常见的选项包括:
- MSS(Maximum Segment Size):最大报文段长度。
- Window Scaling:窗口缩放因子,用于支持更大的窗口大小。
- SACK(Selective Acknowledgment):选择性确认。
- Timestamp:时间戳,用于计算往返时间(RTT)。
- 填充(Padding, 可变长度):用于确保TCP头部的长度是32位的整数倍。
三次握手
- 第一次握手:SYN(Synchronize):发送方(客户端)向接收方(服务器)发送一个TCP报文段,其中:
- SYN标志位设置为1,表示请求建立连接。
- 序列号(Sequence Number)设置为一个随机值(例如Seq = X),作为客户端的初始序列号。
- 确认号(Acknowledgment Number)无意义,因为此时还未收到服务器的序列号。
- 目的:客户端向服务器发起连接请求,并告知自己的初始序列号。
- 第二次握手:SYN + ACK(Synchronize + Acknowledgment):接收方(服务器)收到客户端的SYN报文后,向发送方(客户端)发送一个TCP报文段,其中:
- SYN标志位设置为1,表示同意建立连接。
- ACK标志位设置为1,表示确认客户端的SYN报文。
- 序列号(Sequence Number)设置为一个随机值(例如Seq = Y),作为服务器的初始序列号。
- 确认号(Acknowledgment Number)设置为X + 1,表示期望收到客户端的下一个字节的序号。
- 目的:服务器确认客户端的连接请求,并告知自己的初始序列号。
- 第三次握手:ACK(Acknowledgment):发送方(客户端)收到服务器的SYN + ACK报文后,向接收方(服务器)发送一个TCP报文段,其中:
- ACK标志位设置为1,表示确认服务器的SYN报文。
- 序列号(Sequence Number)设置为X + 1,表示客户端发送的下一个字节的序号。
- 确认号(Acknowledgment Number)设置为Y + 1,表示期望收到服务器的下一个字节的序号。
- 目的:客户端确认服务器的连接请求,双方连接正式建立。
如何查看TCP的连接状态
数据包的长度切分
五、网络层:IP
IP头部
IP头部通常为20字节(如果没有选项字段),最大长度为60字节。以下是IPv4头部的字段:
- 版本(Version, 4位):标识IP协议的版本,对于IPv4,该字段值为4。
- 头部长度(IHL, Internet Header Length, 4位):指示IP头部的长度,以32位字(4字节)为单位,最小值为5(表示20字节),最大值为15(表示60字节)。
- 服务类型(Type of Service, ToS, 8位):用于指定数据包的服务质量(QoS),包括以下子字段:
- 优先级(Precedence, 3位):数据包的优先级。
- 延迟(Delay, 1位):低延迟要求。
- 吞吐量(Throughput, 1位):高吞吐量要求。
- 可靠性(Reliability, 1位):高可靠性要求。
- 成本(Cost, 1位):低成本要求。
- 保留位(Reserved, 1位):必须设置为0。
- 总长度(Total Length, 16位):指示整个IP数据包的长度,包括头部和数据部分,最大值为65535字节。
- 标识(Identification, 16位):用于标识数据包的唯一性,在分片时,同一数据包的所有分片具有相同的标识值。
- 标志(Flags, 3位):用于控制数据包的分片行为,包括以下子字段:
- 保留位(Reserved, 1位):必须设置为0。
- 不分片(DF, Don’t Fragment, 1位):如果设置为1,表示数据包不能被分片。
- 更多分片(MF, More Fragments, 1位):如果设置为1,表示后续还有分片。
- 片偏移(Fragment Offset, 13位):指示当前分片在原始数据包中的位置,以8字节为单位,用于重组分片。
- 生存时间(Time to Live, TTL, 8位):指示数据包在网络中最多可以经过的路由器跳数,每经过一个路由器,TTL值减1,当TTL为0时,数据包被丢弃。
- 协议(Protocol, 8位):指示数据包中封装的上层协议类型,常见值:
- 1:ICMP
- 6:TCP
- 17:UDP
- 头部校验和(Header Checksum, 16位):用于检测IP头部的错误,校验和计算覆盖整个IP头部。
- 源IP地址(Source IP Address, 32位):标识数据包的发送方IP地址。
- 目标IP地址(Destination IP Address, 32位):标识数据包的接收方IP地址。
- 选项(Options, 可变长度):可选字段,用于扩展IP功能。常见的选项包括:
- 记录路由(Record Route):记录数据包经过的路由器IP地址。
- 时间戳(Timestamp):记录数据包经过路由器的时间。
- 松散源路由(Loose Source Routing):指定数据包必须经过的部分路由器。
- 严格源路由(Strict Source Routing):指定数据包必须经过的所有路由器。
- 填充(Padding, 可变长度):用于确保IP头部的长度是32位的整数倍。
如何根据路由表确定源IP地址
假设客户端有多个网卡,就会有多个IP地址,那IP头部的源地址应该选择哪个IP呢?
当存在多个网卡时,在填写源地址IP时,就需要判断到底应该填写哪个地址。这个判断相当于在多块网卡中判断应该使用哪一块网卡来发送包。
这个时候就需要根据路由表规则,来判断哪一个网卡作为源地址IP。
在Linux操作系统,我们可以使用 route -n
命令查看当前系统的路由表。
root@ZB-PF4WQHKS:/mnt/c/Users$ route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.3.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
192.168.10.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
0.0.0.0 192.168.3.1 0.0.0.0 UG 0 0 0 eth0
六、网络接口层:MAC
MAC头部
ARP协议的工作原理
- 目的:ARP用于在局域网中根据目标设备的IP地址查询其MAC地址。
- 过程:
- 发送方检查本地ARP缓存,查看是否已经缓存了目标IP地址对应的MAC地址。
- 如果缓存中没有,发送方会广播一个ARP请求(ARP Request),询问“谁拥有这个IP地址?”
- 目标设备收到ARP请求后,会回复一个ARP响应(ARP Reply),包含自己的MAC地址。
- 发送方收到ARP响应后,将目标IP地址和MAC地址的映射关系缓存到本地ARP表中。
跨网络通信的详细过程
假设发送方的IP地址是192.168.1.100,目标设备的IP地址是10.0.0.50,且它们不在同一个局域网中。
- 步骤1:发送方检查目标IP地址:发送方首先检查目标IP地址10.0.0.50是否在同一个子网内。通过子网掩码(如255.255.255.0)计算,发现10.0.0.50不在192.168.1.0/24网络中。
- 步骤2:发送方将数据包发送到默认网关:发送方知道目标设备不在本地网络,因此会将数据包发送到默认网关(通常是路由器的IP地址,如192.168.1.1)。发送方通过ARP协议获取默认网关的MAC地址:
- 发送方检查本地ARP缓存,查看是否缓存了192.168.1.1的MAC地址。
- 如果没有缓存,发送方会广播ARP请求,询问“谁拥有192.168.1.1?”
- 路由器回复ARP响应,包含自己的MAC地址(如AA:BB:CC:DD:EE:FF)。
- 发送方将192.168.1.1和AA:BB:CC:DD:EE:FF的映射关系缓存到本地ARP表中。
- 步骤3:发送方封装数据包:发送方将数据包封装为以太网帧:
- 目标MAC地址:路由器的MAC地址(AA:BB:CC:DD:EE:FF)。
- 源MAC地址:发送方的MAC地址。
- 目标IP地址:10.0.0.50(目标设备的IP地址)。
- 源IP地址:192.168.1.100(发送方的IP地址)。
- 步骤4:路由器转发数据包:路由器收到数据包后,检查目标IP地址10.0.0.50。路由器根据路由表决定如何转发数据包:
- 如果目标网络直接连接到路由器,路由器会通过ARP协议获取目标设备的MAC地址,并将数据包转发到目标设备。
- 如果目标网络需要通过其他路由器访问,路由器会将数据包转发到下一跳路由器。
- 步骤5:目标设备接收数据包:目标设备收到数据包后,检查目标IP地址是否匹配自己的IP地址。如果匹配,目标设备处理数据包并生成响应。
跨网络通信中的MAC地址变化
在跨网络通信中,数据包的MAC地址会随着经过的路由器而变化:
- 发送方到路由器:
- 目标MAC地址:路由器的MAC地址。
- 源MAC地址:发送方的MAC地址。
- 路由器到目标设备:
- 目标MAC地址:目标设备的MAC地址。
- 源MAC地址:路由器的MAC地址。
七、网卡
网卡负责把数字信息转化成电信号,然后在网线上传输。
网卡驱动获取网络包之后,会将其复制到网卡内的缓存区中,接着会在其开头加上报头和起始帧分界符,在末尾加上用于检测错误的帧校验序列。
起始帧分界符是一个用来表示包起始位置的标记。
末尾的FCS(帧校验序列)用来检查包传输过程是否有损坏。
最后网卡会将包转为电信号,通过网线发送出去。
八、交换机
交换机的设计是将网络包原样转发到目的地。
交换机工作在MAC层,也称为二层网络设备。
交换机的包收发工作
- 首先,电信号到达网线接口,交换机里的模块进行接收,接下来交换机里的模块将电信号转换为数字信号。
- 然后通过包末尾的FCS校验错误,如果没问题则放到缓冲区。这部分操作基本和计算机的网卡相同,但交换机的工作方式和网卡不同。
- 计算机的网卡本身具有MAC地址,并通过核对收到的包的接收方MAC地址判断是不是发给自己的,如果不是发给自己的则丢弃;交换机的端口不具有MAC地址。 交换机的端口不核对接收方MAC地址,而是直接接收所有的包并存放到缓冲区中,接下来需要查询一下这个包的接收方MAC地址是否已经在MAC地址表中有记录了。
如果地址表中找不到指定的MAC地址,这可能是因为具有该地址的设备还没有向交换机发送过包,或者这个设备一段时间没有工作导致地址被从地址表中删除了。
这种情况下,交换机无法判断应该把包转发到哪个端口,只能将包转发到除了源端口之外的所有端口上,无论该设备连接在哪个端口上都能收到这个包。
此外,如果接收方MAC地址是一个广播地址,那么交换机会将包发送到除源端口之外的所有端口。 以下两个属于广播地址:
- MAC地址中的FF:FF:FF:FF:FF:FF
- IP地址中的255.255.255.255
九、路由器
路由器是基于IP设计的,俗称三层网络设备,路由器的各个端口都具有MAC地址和IP地址;而交换机是基于以太网设计的,俗称二层网络设备,交换机的端口不具有MAC地址。
路由器的包收发工作
- 首先,电信号到达网线接口部分,路由器中的模块会将电信号转成数字信号。
- 然后通过包末尾的FCS进行错误校验。
- 如果没问题则检查MAC头部中的接收方MAC地址,看看是不是发给自己的包,如果是就放到接收缓冲区中,否则就丢弃这个包。 总的来说,路由器的端口都具有MAC地址,只接收与自身地址匹配的包,遇到不匹配的包则直接丢弃。
- 完成包接收操作之后,路由器就会去掉包开头的MAC头部。 MAC头部的作用就是将包送达路由器,其中的接收方MAC地址就是路由器端口的MAC地址。因此,当包到达路由器之后,MAC头部的任务就完成了,于是MAC头部就会被丢弃。
- 接下来,路由器会根据MAC头部后方的IP头部中的内容进行包的转发操作。 转发操作分为几个阶段,首先是查询路由表判断转发目标。
接下来就会进入包的发送操作。 首先,我们需要根据路由表的网关列判断对方的地址。
- 如果网关是一个IP地址,则这个IP地址就是我们要转发到的目标地址,还未抵达终点,还需继续需要路由器转发。
- 如果网关为空,则IP头部中的接收方IP地址就是要转发到的目标地址,也是就终于找到IP包头里的目标地址了,说明已抵达终点。
知道对方的IP地址之后,接下来需要通过ARP协议根据IP地址查询MAC地址,并将查询的结果作为接收方MAC地址。 路由器也有ARP缓存,因此首先会在ARP缓存中查询,如果找不到则发送ARP查询请求。
接下来是发送方MAC地址字段,这里填写输出端口的MAC地址。还有一个以太类型字段,填写0800(十六进制)表示IP协议。
网络包完成后,接下来会将其转换成电信号并通过端口发送出去。这一步的工作过程和计算机也是相同的。
发送出去的网络包会通过交换机到达下一个路由器。由于接收方MAC地址就是下一个路由器的地址,所以交换机会根据这一地址将包传输到下一个路由器。 接下来,下一个路由器会将包转发给再下一个路由器,经过层层转发之后,网络包就到达了最终的目的地。在网络包传输的过程中,源IP和目标IP始终是不会变的,一直变化的是MAC地址,因为需要MAC地址在以太网内进行两个设备之间的包传输。
十、接收数据
网络接口层处理
数据包首先到达网络接口层,服务器将解析以太网帧头部,检查目标MAC地址字段。若MAC地址匹配服务器的网络接口地址,则接收该数据包;否则丢弃。
网络层处理
服务器去除以太网帧头部,暴露IP数据报。检查IP数据报的目标IP地址,若与服务器IP地址匹配,则继续处理。查看IP头部的协议字段,确定上层传输协议为TCP。
传输层处理
解析TCP段头部信息,包括序列号、端口号等关键字段。检查序列号是否符合预期,若符合则将数据存入缓存并发送ACK确认应答。确认目标端口号,发现该端口正处于HTTP服务监听状态。
应用层处理
HTTP服务进程接收数据,解析HTTP请求内容。根据请求内容生成相应的HTTP响应报文。对响应报文进行封装,依次添加TCP、IP、以太网帧头部。设置源地址为服务器IP地址,目标地址为客户端IP地址。
数据传输过程
封装完成的响应数据包通过服务器网卡发送。经过网络交换机转发至出口路由器。路由器根据目标IP地址进行路径选择和转发。数据包经过多个路由器接力传输。最终到达客户端所在网络的边界路由器。
客户端接收处理
边界路由器将数据包转发至内部交换机。交换机根据MAC地址将数据包转发至目标客户端。客户端解析数据包,去除各层头部,提取HTTP响应内容。浏览器进程接收HTTP响应,进行页面渲染和显示。
连接终止
客户端发起TCP连接终止过程,执行四次握手。服务器响应客户端的终止请求。双方完成连接释放,通信结束。