1. 引言
计算机网络是每位计算机学者的必修课,也是各大厂面试中的重点考察内容。本文将从后端开发的角度,整理出高效的知识点。考虑到时间有限,本文将侧重于知识的性价比,建议有时间的同学更系统地学习。
我们以一个经典问题引入话题:当浏览器地址栏输入www.baidu.com
时,发生了什么?
2. 重点知识
2.1. DNS解析
以首次访问为例,DNS解析涉及多个层次:浏览器缓存、系统缓存、Hosts文件、路由器缓存和递归DNS服务器。
浏览器缓存
每个浏览器都有自己的DNS缓存,记录常用域名与IP地址的对应关系(带有过期时间)。当浏览器缓存未命中时,它会查询系统缓存。如果你使用Chrome浏览器,可以在地址栏输入chrome://net-internals/#dns
来查看当前的DNS缓存。
系统缓存
浏览器会进行系统调用,查询RAM中的DNS缓存。你可以使用nslookup
命令手动检查是否存在对应域名的缓存(适用于Linux和MacOS)。如果没有命中缓存,浏览器将继续查询Hosts文件。
Hosts文件
Hosts文件包含用户手动配置的域名与IP的映射。在许多公司的内网中,常用来配置数据库、中间件或其他对IP敏感的服务的域名映射。你可以通过修改/etc/hosts
文件来进行自定义配置。
递归DNS服务器
如果Hosts文件未找到对应映射,浏览器会查询路由器缓存。如果路由器缓存也未命中,浏览器将递归查询本地DNS服务器。这个递归过程涉及根域名、顶级域名和权威域名的逐层查询。
当本地DNS服务器无法找到目标域名(如baidu.com
)时,查询将继续进行。这时,服务器会迭代地访问根域名服务器、顶级域名服务器和权威域名服务器,以获取对应的IP地址。具体而言,本地服务器首先向根域名服务器查询baidu.com
,得到目标域名所在地区的顶级域名服务器的IP地址。然后,本地DNS服务器根据该IP地址访问顶级域名服务器,继续迭代,直到找到baidu.com
的IP地址。
为了更好地理解这一过程,我们可以在终端模拟本地DNS服务器迭代查询目标域名(例如bilibili.com
)。使用dig
命令进行DNS记录查询时,首先我们向根域名服务器找到了包含bilibili.com
的.com
顶级域名服务器地址。接下来,我们可以使用任意一个顶级域名服务器的IP地址继续查询bilibili.com
的IP地址。
需要注意的是,实际操作中,当我执行dig
命令时,本地DNS服务器通常会直接命中缓存,而无需再向根域名服务器进行查询,因此后续的查询过程不再演示。
2.2. ARP解析
ARP解析是在局域网内确定IP地址对应的MAC地址的过程,也涉及多个层次:本地ARP缓存、ARP请求和ARP应答。
本地ARP缓存
每台计算机都有自己的ARP缓存,用于存储已解析的IP地址与MAC地址的映射关系。当需要发送数据包到特定IP地址时,系统会首先检查本地ARP缓存。如果缓存中已有对应的MAC地址,则直接使用该地址进行数据传输。我们可以通过arp -a
命令来查看当前系统的ARP缓存(适用于Linux和MacOS):
执行命令 arp -a
显示了系统中的ARP缓存,下面是每一行的解释:
-
IP地址:每一行的第一个部分是IP地址,例如
192.168.115.1
。 -
MAC地址:紧随其后的是对应的MAC地址,例如
6c:92:bf:7f:29:f5
。 -
接口:
on en0
表示该IP地址与en0
接口(通常是以太网接口或无线网络接口)相关联。 -
ifscope:指示这个ARP条目是有效的,表示它是针对特定接口的。
-
永久:有些条目(例如
mdns.mcast.net
和239.255.255.250
)标记为“permanent”,表示这些条目是持久的,不会过期。 -
广播地址:
192.168.115.255
对应的MAC地址是ff:ff:ff:ff:ff:ff
,这是一个广播地址,表示发送给网络中所有设备。
ARP请求
如果本地ARP缓存未命中,系统会发送ARP请求广播包,询问网络中“谁拥有这个IP地址?”该请求包会被网络中的所有设备接收。
ARP应答
拥有该IP地址的设备收到ARP请求后,会发送ARP应答,包含其MAC地址。这个应答包是单播的,直接发回请求的设备。
更新ARP缓存
一旦接收到ARP应答,请求的设备将新的IP地址与MAC地址的映射关系存入本地ARP缓存,以便于后续请求时快速访问。
通过以上步骤,ARP解析能够有效地将目标IP地址转换为对应的MAC地址,以实现数据包在局域网中的正确传输。
2.3. 建立连接
一旦获取到IP地址,浏览器会通过该地址与目标服务器建立TCP连接,通常使用HTTP的默认端口80,或者HTTPS的端口443。这一过程被称为“TCP的三次握手”。
TCP报文
TCP是一种面向连接的可靠全双工通信协议,其报文头格式如下:
相关字段含义如下(每个字段都十分重要),这些字段总和为20字节,即TCP报文头的长度:
Name | Desc | Size (bits) |
---|---|---|
Source Port | 源端口 | 16 |
Destination Port | 目的端口 | 16 |
Sequence Number | 序列号(seq),在TCP传输流中,每个字节按顺序编号。当SYN=1 时即为初始序列号(ISN),否则为当前数据段的第一个字节的序列号。 | 32 |
Acknowledgment Number | 确认号(ack),表示接收方期望收到下一个TCP报文段的第一个字节的序列号,通常为seq+1 。 | 32 |
Header Length | 首部长度,指数据部分起始处与TCP数据段起始处的字节偏移量,确定TCP数据段头部的长度。 | 4 |
Reserved | 保留字段,当前必须全部为0。包含控制位: - CWR:拥塞窗口减少 - ECE:ECN回显 - URG:紧急数据 - ACK:确认号有效 - PSH:立即推送数据 - RST:重置连接 - SYN:同步序号 - FIN:标记数据发送完毕 | 4 |
Window Size | 窗口大小,从Ack Number开始还能接收多少字节的数据,表示当前接收端的接收窗口剩余空间。 | 16 |
TCP Checksum | 校验位,确认传输的数据是否损坏,发送端和接收端生成的值必须相同。计算基于伪头+TCP头+TCP数据。 | 16 |
Urgent Pointer | 紧急指针,仅在URG控制位为1时有效,指出本数据段中紧急数据的字节数。 | 16 |
Option | 可选项字段,长度不定,但长度必须是32 bits的整数倍。 | 32X |
三次握手
三次握手可以用打电话的场景来生动说明,假设甲要和乙通话:
甲:喂,听得到吗?
乙:听得到,你呢?
甲:我也听得到,咱们说正事。
开始时,双方都是CLOSED
状态。甲作为客户端主动发起连接,乙作为服务端被动接收连接。服务端的TCP进程创建传输控制块(TCB),进入LISTEN
监听状态。
第一次握手:客户端创建TCB,向服务端发送请求,报文头中的SYN=1
,表示初始序列号seq=x
,此时客户端进入SYN-SENT
状态。
第二次握手:服务端收到请求后,如果同意连接,向客户端发送确认报文,包含ACK=1
和SYN=1
,初始化序列号seq=y
,并确认上一个报文ack=x+1
,此时服务端进入SYN-RCVD
状态。
第三次握手:客户端收到确认后,再次确认,报文中ACK=1
,序列号seq=x+1
,同时确认上一个报文ack=y+1
,至此TCP连接建立,客户端进入ESTABLISHED
状态。
为什么需要三次握手?第一次证明客户端发送能力正常,第二次确认服务端的发送和接收能力,第三次确保客户端接收能力正常。
如果只有两次握手,可能导致状态不一致。假设第一次握手后请求滞留在网络中,客户端未收到确认,可能重新发起连接。此时,服务端会建立两个连接,导致状态不对等。
三次握手可以有效抵御网络波动,确保连接的可靠性。
四次挥手
我们可以将这部分内容简化,使其更清晰和易于理解。以下是优化后的版本:
数据传输完毕后,双方可以释放连接。最开始,客户端和服务器都处于ESTABLISHED
状态,客户端主动关闭,服务器被动关闭。
第一次挥手:客户端发出连接释放报文,停止发送数据。报文首部中FIN=1
,序列号为seq=u
(即最后一个传送字节的序号加1),此时客户端进入FIN-WAIT-1
状态。
第二次挥手:服务端收到释放报文,发送确认报文,ACK=1
,ack=u+1
,并带上自己的序列号seq=v
,此时服务端进入CLOSE-WAIT
状态。
第三次挥手:客户端接收到服务端的确认,发送FIN=1
、ACK=1
的报文,序列号seq=w
(通常是v+1
),ack=u+1
,客户端进入FIN-WAIT-2
状态,等待服务器的释放报文。服务器发送完最后的数据后,发出连接释放报文,进入LAST-ACK
状态,等待客户端确认。
第四次挥手:客户端收到服务端的释放报文后,发送确认ACK=1
,ack=w+1
,序列号seq=u+1
,此时进入TIME-WAIT
状态。虽然连接尚未终止,但客户端需要等待2MSL(最大报文生存时间,通常为2分钟),直到撤销相应的TCB后,才会进入CLOSED
状态。服务器在收到确认后立即进入CLOSED
状态,TCP连接至此断开,四次挥手完成。
为什么客户端要等待2MSL?
这主要是为了确保最后发送的ACK报文能到达服务端。如果ACK报文丢失,服务端会在2MSL内重发第三次挥手,增加了容错性。
2.4. 优化技术
连续ARQ协议
TCP协议通过使用连续ARQ协议和滑动窗口协议来确保数据传输的可靠性。
ARQ(自动重传请求)是一种错误纠正协议,适用于OSI模型中的数据链路层和传输层。它通过确认和超时机制,在不可靠服务的基础上实现可靠传输。如果发送方在一定时间内未收到确认帧,通常会重新发送数据。ARQ协议包括停止等待ARQ和连续ARQ,具备错误检测、正面确认、超时重传和负面确认及重传等机制。
连续ARQ协议:为了提高信道利用率,连续ARQ协议允许发送方连续发送一组数据包,而无需在每个数据包后等待确认。这种方式称为流水线传输,发送方可以在未收到ACK时继续发送多个分组,提升了传输效率。
滑动窗口
滑动窗口是一种流量控制技术,旨在提高网络通信的效率。早期网络中,发送方往往不知道网络拥堵情况,导致数据包在中间节点被阻塞和丢失。为了解决这个问题,滑动窗口应运而生。
滑动窗口允许发送方在接收方未确认之前,连续发送多个数据包。接收方会通过窗口尺寸字段(Window Size
)告知发送方可以发送多少数据。
在TCP中,滑动窗口的大小表示接收方的缓冲区容量。发送方根据这个大小决定要发送多少字节的数据。当窗口为0时,发送方通常停止发送数据。滑动窗口还用于实现ACK确认、流量控制和拥塞控制等功能。
拥塞控制
拥塞控制的目标是确保数据传输速率与网络承载能力匹配,从而实现高效和公平的网络使用。拥塞控制算法主要分为四个阶段:
-
慢启动(Slow Start):
- 连接开始时,TCP拥塞窗口(cwnd)从一个较小的值(通常是一个段的大小)开始。
- 每收到一个确认(ACK),cwnd加倍,导致窗口大小快速增长。
- 当cwnd达到阈值(ssthresh)时,转入拥塞避免阶段。
-
拥塞避免(Congestion Avoidance):
- 在这一阶段,每经过一个往返时间(RTT),cwnd增加1个最大段大小(MSS)。
- 这种增长速度较慢,有助于防止网络拥塞。
-
快重传和快恢复(Fast Retransmit and Fast Recovery):
- 当接收方连续收到三个重复的ACK时,发送方会立即重传丢失的数据包,而不是等待重传计时器。
- 快恢复算法会调整ssthresh的值,并将cwnd设置为ssthresh加上3个MSS的大小,然后进入拥塞避免阶段。
HTTP版本比较
HTTP(超文本传输协议)随着时间演变,版本间在性能和安全性上进行了多次改进。以下是HTTP 1.0、1.1、2.0和3.0的主要区别:
特性 | HTTP 1.0 | HTTP 1.1 | HTTP 2.0 | HTTP 3.0 |
---|---|---|---|---|
连接 | 非持久连接,每个请求后关闭TCP连接 | 默认持久连接,减少连接开销 | 使用二进制分帧,多路复用请求 | 基于QUIC,减少连接建立时间 |
请求 | 请求与响应独立,无优先级或多路复用 | 支持请求管线化,在一个连接中发送多个请求 | 同时发送多个请求,解决队头阻塞 | 改进的拥塞控制和无缝迁移连接 |
头部 | 头部信息重复发送,增加开销 | 引入更多缓存控制头部,如Cache-Control | 头部压缩(HPACK),减少开销 | 默认使用TLS 1.3进行加密,提高安全性 |
缓存 | 缓存机制较弱,不支持ETag等头部 | 增强的缓存机制 | 提供更高效的缓存机制 | 内置安全性 |
特点 | 每个请求都需要建立新的连接 | 允许多个请求在同一连接上进行 | 提高了传输效率和资源利用率 | 提升移动性,改进的拥塞控制 |
HTTPS原理
HTTPS(HTTP over SSL)是一种安全的传输协议,通过在HTTP上增加SSL/TLS层来保障数据的安全性。
特性 | SSL | TLS |
---|---|---|
开发者 | Netscape公司 | IETF(互联网工程任务组) |
首次发布 | 1994年(SSLv2),1995年(SSLv3) | 1999年(TLS 1.0) |
主要功能 | 提供私密性、信息完整性和身份认证 | 提供保密性和数据完整性 |
版本 | SSLv1(未发布)、SSLv2、SSLv3 | TLS 1.0、1.1、1.2、1.3 |
安全性 | 安全性较弱,存在多个已知漏洞 | 提升了安全性,修复了SSL中的一些漏洞 |
SSL(安全套接层)握手是客户端和服务器建立安全连接的过程,确保数据在传输过程中的保密性和完整性。以下是TLS/SSL握手的详细步骤:
-
客户端Hello:
- 客户端发送一个
Hello
消息,包含支持的TLS版本、加密套件列表和生成的随机数。
- 客户端发送一个
-
服务器Hello:
- 服务器回应一个
Hello
消息,选择一个TLS版本和加密套件,同时发送自己的随机数。
- 服务器回应一个
-
服务器证书:
- 服务器向客户端发送其数字证书,包含公钥和其他身份信息。
-
服务器密钥交换(可选):
- 服务器可能发送一个密钥交换消息,用于协商密钥材料。
-
请求客户端证书(可选):
- 服务器可以请求客户端提供证书以进行身份验证。
-
客户端证书(可选):
- 如果请求,客户端发送其数字证书。
-
客户端密钥交换:
- 客户端生成预主密钥(pre-master secret),用服务器的公钥加密后发送给服务器。
-
生成会话密钥:
- 客户端和服务器使用预主密钥以及之前交换的随机数生成对称密钥(会话密钥)。
-
结束握手:
- 客户端发送
Finished
消息,表明握手结束,并开始加密数据传输。 - 服务器也发送
Finished
消息,确认握手成功。
- 客户端发送
-
加密通信:
- 一旦握手完成,客户端和服务器开始使用会话密钥进行加密的双向通信。
SSL握手过程确保客户端和服务器之间建立安全连接。通过公钥加密和数字证书,保证了密钥交换的安全性和双方身份的验证。即使在不安全的网络环境中,这一过程也能有效保护通信的机密性和完整性。
常见状态码
状态码 | 类别 | 含义 |
---|---|---|
100 | 信息性状态码 | Continue:继续发送请求 |
101 | 信息性状态码 | Switching Protocols:切换协议 |
200 | 成功状态码 | OK:请求成功 |
201 | 成功状态码 | Created:成功创建新资源 |
202 | 成功状态码 | Accepted:请求已接受,尚未处理 |
204 | 成功状态码 | No Content:请求成功,但无内容 |
301 | 重定向状态码 | Moved Permanently:永久重定向 |
302 | 重定向状态码 | Found:临时重定向 |
303 | 重定向状态码 | See Other:在另一个URI找到响应 |
304 | 重定向状态码 | Not Modified:未修改,可使用缓存版本 |
307 | 重定向状态码 | Temporary Redirect:临时重定向 |
400 | 客户端错误状态码 | Bad Request:请求格式错误 |
401 | 客户端错误状态码 | Unauthorized:需要用户认证 |
403 | 客户端错误状态码 | Forbidden:拒绝执行请求 |
404 | 客户端错误状态码 | Not Found:资源不存在 |
405 | 客户端错误状态码 | Method Not Allowed:不允许的方法 |
408 | 客户端错误状态码 | Request Timeout:请求超时 |
500 | 服务器错误状态码 | Internal Server Error:服务器内部错误 |
501 | 服务器错误状态码 | Not Implemented:不支持请求的功能 |
502 | 服务器错误状态码 | Bad Gateway:无效的响应 |
503 | 服务器错误状态码 | Service Unavailable:服务器无法处理请求 |
504 | 服务器错误状态码 | Gateway Timeout:网关未及时收到响应 |
505 | 服务器错误状态码 | HTTP Version Not Supported:不支持的HTTP协议版本 |
3. 其他
3.1. 浏览器渲染
浏览器渲染页面的原理可以概括为以下几个主要步骤:
-
解析HTML构建DOM树:从服务器获取HTML后,解析并构建DOM(文档对象模型)树,反映页面结构。
-
解析CSS构建CSSOM树:解析CSS,构建CSSOM(CSS对象模型)树,包含所有样式规则。
-
构建渲染树:结合DOM树和CSSOM树,生成渲染树,只包含可见节点及其样式。
-
布局(Layout):计算渲染树中每个节点的确切位置和大小,进行重排(Reflow)。
-
绘制(Painting):根据布局信息将内容绘制到屏幕上,进行重绘(Repaint)。
-
合成(Compositing):将页面不同部分绘制到不同层上,然后合成显示,以提高渲染性能。
这个过程是逐步进行的,了解这些步骤可以帮助开发者优化网页性能。