计算机网络基础

这是人工智能训练师基础系列的第六章。计算机网络是知识体系里的重点章节,核心概念必须能讲明白——OSI 模型、TCP/UDP、HTTP/HTTPS、DNS、IP 地址与子网划分这几块都要落到细节。这一章的核心问题就一个:”数据怎么传”——从你按下回车到网页打开,中间到底发生了什么。下面跟着串讲走一遍,遗忘的内容就能捡回来。


计算机网络:数据怎么传

网络是重点章节,概念多但相对好理解。

OSI与TCP/IP模型

OSI 七层模型从下到上:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。用”寄快递分层”来类比很好记:物理层管”用什么车走什么路”(比特流传输);数据链路层管”两个相邻站点之间怎么可靠传一帧”(MAC 地址寻址,以太网、Wi-Fi 在这层);网络层管”包裹怎么从源头路由到目的地”(IP 协议在这层);传输层管”端到端的一次完整通信”(TCP/UDP,端口号);会话层管”建立、管理、终止会话”;表示层管”数据怎么编码、加密、压缩”;应用层管”给用户应用提供网络服务”(HTTP、FTP、DNS、SMTP)。

实际中会话层和表示层基本并入应用层,所以 TCP/IP 四层模型更贴近现实:网络接口层、网际层(IP)、传输层(TCP/UDP)、应用层。也有教材把 TCP/IP 写成五层模型,是一回事。

会话层与表示层详解

会话层和表示层在 TCP/IP 里虽然被并入应用层,但它们的职责值得单独拎出来说清楚,面试题里常考。

会话层管的”建立、管理、终止会话”到底是什么?你可以把它想象成打电话——拨号建立连接(建立会话)、通话过程中保持连接(管理会话)、挂断结束(终止会话)。具体来说,会话层负责协调两个应用进程之间的通信节奏,比如什么时候开始传、什么时候暂停、什么时候结束。它还能做”断点续传”——比如你下载一个大文件中途断网了,下次连上能从断点继续,而不是从头开始,这就是会话层在记录传输位置。还有远程登录(比如 SSH)时,会话层会维护一个虚拟终端会话,保证你的键盘输入和屏幕输出能正确对应。

表示层管”数据怎么编码、加密、压缩”,这三个词看着抽象,咱们一一对应到你熟悉的操作。编码就是把数据从一种格式转成另一种格式,比如你在浏览器里输入中文,计算机要把中文转成 UTF-8 编码才能在网络上传输,这就是编码;再比如 JPEG 图片格式,它是把像素数据压缩编码成 JPEG 格式的二进制流,这也是编码——所以 JPEG 和你知道的 PNG、GIF 一样都是图片格式,它的处理属于编码的一种。加密就更好理解了,SSH 登录远程服务器时,你的密码不会明文传出去,而是被加密了;HTTPS 里的 SSL/TLS 也是在做加密。压缩就是把数据变小,比如你用 WinRAR 压缩文件,或者 HTTP 传输时对文本数据做 gzip 压缩,都是表示层干的活。所以表示层就像一个”数据加工厂”,把原始数据加工成适合传输的格式。

TCP/IP模型命名由来

TCP/IP 四层模型为什么叫这个名字?因为它的两个核心协议是 TCP(传输控制协议)和 IP(网际协议),这两个协议是整个互联网的基石,所以用它们来命名整个协议族。你可以把 TCP/IP 想象成一个公司的名字,TCP 和 IP 是公司里最重要的两个部门,一个管运输(TCP),一个管路由(IP)。

路由器与WIFI的层级归属

为什么路由器是网络层设备,而 WIFI 属于数据链路层?这里的关键是看它们工作时用什么地址来转发数据。路由器工作在网络层,它根据 IP 地址来决定怎么把包从一个网络转发到另一个网络——比如你家里的路由器,它知道 192.168.1.x 这个网段的包该往内网发,其他包该往外网发,靠的就是 IP 地址判断。而 WIFI(准确说是 IEEE 802.11 协议族)工作在数据链路层,它只关心同一个局域网内的设备之间怎么通信,用的是 MAC 地址——你的手机连 WIFI 时,数据在手机和路由器之间传输,靠的是 MAC 地址来识别对方。WIFI 具体使用的是 IEEE 802.11 系列协议,比如 802.11a/b/g/n/ac/ax,这些协议定义了无线传输的物理层规范和数据链路层的帧格式。

PPP、ICMP、ARP协议详解

PPP(点对点协议)主要是做什么约定的?你可以把它想象成两个人打电话时约定”我们说普通话,语速慢一点,每句话说完我会说’收到’确认一下”。PPP 就是在两个点到点连接的设备之间(比如你的电脑通过拨号连到 ISP),约定好数据怎么打包、怎么校验、怎么协商参数(比如要不要压缩、要不要认证)。它解决的是”点对点连接上怎么可靠地传数据”这个问题。

ICMP(互联网控制报文协议)是 Ping 使用的协议,为什么 Ping 一下 IP 或域名就能知道连通性?Ping 的原理很简单:你的电脑向目标 IP 发一个 ICMP Echo Request(回显请求)包,目标收到后如果正常,就回一个 ICMP Echo Reply(回显应答)包。如果你收到了这个回复,就说明网络是通的;如果没收到,就说明中间断了。Ping 还会告诉你往返时间(RTT),也就是包从发出去到回来花了多久,时间越长说明网络越慢。

ARP(地址解析协议)负责把 IP 地址解析成 MAC 地址。这个过程是怎样的?假设你的电脑想和同一个局域网内的另一台电脑通信,但只知道对方的 IP 不知道 MAC。这时你的电脑会发一个 ARP 请求广播,问”谁是 192.168.1.10?请告诉我你的 MAC 地址”。局域网内所有电脑都能收到这个广播,但只有 IP 是 192.168.1.10 的那台会回复”我是 192.168.1.10,我的 MAC 地址是 AA:BB:CC:DD:EE:FF”。你的电脑收到回复后,就把 IP 和 MAC 的对应关系存在 ARP 缓存里,下次再发数据时直接查缓存就行。

MAC 地址是设备唯一的,它是网卡出厂时就烧录在硬件里的,全球唯一,不会重复。为什么会有 IP→MAC 的解析关系?因为网络层用 IP 地址来找目标主机,但数据链路层需要 MAC 地址才能在局域网内传输——就像你寄信时,国家之间靠邮政编码(IP)来分拣,但最后送到家门口需要门牌号(MAC)。ARP 就是那个”查门牌号”的服务。

记忆口诀(从下到上):物、数、网、传、会、表、应。每层对应的设备:物理层有中继器、集线器(hub);数据链路层有交换机(switch)、网桥;网络层有路由器(router);传输层以上是网关、防火墙。

每层对应的常见协议也得知道一两个,否则题目里给你一个协议名问你属于哪层你答不上来。物理层主要是电气规范,比如以太网的物理层规范 IEEE 802.3;数据链路层有以太网协议(Ethernet)、PPP(点对点协议);网络层有 IP(IPv4/IPv6)、ICMP(就是 ping 用的那个)、ARP(把 IP 解析成 MAC 地址);传输层有 TCP 和 UDP;会话层和表示层在 TCP/IP 体系里基本被并入应用层,可以记 RPC、SSL/TLS、JPEG 这类做编码加密的活儿;应用层协议最多,HTTP、HTTPS、FTP、SMTP、DNS、SSH、DHCP 都在这一层。看到一个协议名你能马上反应它在第几层,这是基本盘。

数据封装过程也要会:发送方从上到下,每经过一层加一个首部(应用数据→加 TCP 头成段 segment→加 IP 头成包 packet→加帧头帧尾成帧 frame→变成比特流);接收方反过来一层层剥。这个”封装—解封装”是重点知识。

数据封装过程实例

光说”加头加头加头”还是抽象,咱们把一次具体的网页请求跟着走一遍。假设你在浏览器里输入了一个网址,要发一段”Hello”给服务器,数据从你的电脑一层层被”穿衣服”再发出去的过程是这样的:

  • 第一步(应用层):浏览器把”Hello”加上一个 HTTP 请求头,里面写着”GET / HTTP/1.1”、Host、User-Agent 这些字段。这时数据叫”消息”(message)。
  • 第二步(传输层):TCP 给它加上 TCP 头,头里包含源端口号(比如你的浏览器临时端口 54321)、目的端口号(HTTP 默认 80)、序号 seq、确认号 ack、控制标志 SYN/ACK/FIN 等。这时数据叫”段”(segment)。
  • 第三步(网络层):IP 再加上 IP 头,头里包含源 IP(你的本机 IP,比如 192.168.1.10)、目的 IP(服务器的 IP,比如 93.184.216.34)、TTL(生存时间,防止数据包在网络里无限循环)等。这时数据叫”包”(packet)。
  • 第四步(数据链路层):再加上帧头(包含源 MAC 地址和目的 MAC 地址,MAC 是网卡的物理地址)和帧尾(FCS 帧校验序列,用于接收方检查数据有没有传错)。这时数据叫”帧”(frame)。
  • 第五步(物理层):帧被转成比特流,通过网线或无线电波变成电信号或光信号一比特一比特发出去。

到了服务器那边,接收方反过来一层层剥:物理层把比特流组装成帧→数据链路层校验 FCS、剥掉帧头帧尾→网络层读 IP 头看目的 IP 是不是自己→传输层读 TCP 头交给对应端口的进程→应用层读 HTTP 头把”Hello”交给 web 服务器处理。一层对应一层,谁加的谁剥,谁也不越俎代庖。这个”层层加头、层层剥头”的过程就是封装和解封装,理解了它你就理解了分层模型的本质——每层只管自己那一层的活儿,不关心上下层在干什么。

TCP与UDP

TCP 像打电话要确认:建立连接(三次握手)、传输时确认收到、丢了重传、按顺序到达,可靠但慢,开销大。UDP 像寄明信片:发出去就不管了,不建连接、不确认、不重传、不保证顺序,不可靠但快、开销小。

TCP三次握手详解

光说”SYN、SYN+ACK、ACK”还是抽象,咱们先画个图再带具体数字走一遍。三次握手的过程就像两个人确认通话:

1
2
3
4
5
6
7
8
9
10
11
客户端(C)                服务器(S)
| |
|---- SYN (seq=x) ------->| 第一次:C说"我能发"
| | S确认"C能发",进入SYN_RCVD
|<-- SYN+ACK (seq=y, |
| ack=x+1) -----------| 第二次:S说"我能发也能收"
| | C确认"S能发也能收",进入ESTABLISHED
|---- ACK (seq=x+1, |
| ack=y+1) ----------->| 第三次:C说"我也能收"
| | S确认"C能收",进入ESTABLISHED
| |

假设客户端初始序号 seq=x,咱们设 x=1000;服务器初始序号 seq=y,咱们设 y=5000。

  • 第一次握手:客户端发 SYN 报文,seq=1000。SYN 报文的作用是什么?它不是请求数据,而是请求建立连接——告诉服务器”我想跟你建立连接,我的初始序号是 1000”。这时客户端进入 SYN_SENT 状态,等待服务器响应。
  • 第二次握手:服务器收到 SYN 后回 SYN+ACK,seq=5000,ack=1001。这里的”+”号不是拼接的意思,而是表示这个报文里同时设置了 SYN 和 ACK 两个标志位——就像一个人同时说”我同意建立连接(SYN)”和”我收到你刚才说的话了(ACK)”。服务器既确认收到了客户端的 SYN(ack=1001 表示”我收到你 1000 了,你下一个发 1001”),又告诉客户端自己的初始序号是 5000。这时服务器进入 SYN_RCVD 状态。
  • 第三次握手:客户端收到 SYN+ACK 后回 ACK,seq=1001,ack=5001。客户端确认收到服务器的 SYN(ack=5001 表示”我收到你 5000 了,你下一个发 5001”)。这时双方都进入 ESTABLISHED 状态,连接建立。

现在解释一下 SYN 和 ACK 数值增加的作用。SYN 报文中的 seq 是发送方的初始序号,告诉对方”我接下来发的数据就从这个号开始算”。ACK 报文中的 ack 是确认号,它等于收到的 seq + 1,表示”我已经收到 seq 这个序号之前的所有数据了,你可以从 seq+1 开始发”。比如服务器收到客户端的 SYN(seq=1000),就回 ack=1001,意思是”我收到你的初始序号 1000 了,你下一个包的序号应该是 1001”。这个机制确保了数据的可靠传输——每发一个包,对方都要确认收到,序号就是用来对账的。

为什么两次握手不行?这里得从”双向确认”的角度想。建立 TCP 连接是为了双方都能发能收,所以两个方向各要确认一次”我能发”和”你能收”。第一次握手,服务器确认了客户端能发;第二次握手,客户端确认了服务器能收、也能发;第三次握手,服务器确认了客户端能收。两次握手只能让客户端确认服务器的发送和接收能力,但服务器还没确认客户端的接收能力——万一是网络里滞留的一个旧连接请求呢?如果只两次握手,服务器一收到 SYN 就建立连接、分配资源,结果这个请求是个迟到几小时的旧包,那服务器就白建一个连接白占资源了。三次握手多一步确认,就能让旧包没法错误地建立连接,因为客户端根本没发过这个 SYN,不会回第三次的 ACK。

三次握手过程中,什么时候可以传递真实数据?答案是第三次握手之后,也就是双方都进入 ESTABLISHED 状态之后。不过有一种优化叫”捎带数据”——第三次握手的 ACK 报文里可以顺便带上客户端要发的第一批数据,这样不用等连接建立后再单独发一个数据报文,节省了一个 RTT。比如客户端想发”Hello”给服务器,可以在第三次握手的 ACK 报文里把”Hello”一起发过去,服务器收到后就可以直接处理了。

TCP四次挥手详解

接着上面的序号继续。假设现在数据传完了,客户端要主动断开连接。当前客户端 seq=1001,ack=5001。

先画个图看清楚四次挥手的过程:

1
2
3
4
5
6
7
8
9
10
11
12
客户端(C)                服务器(S)
| |
|---- FIN (seq=x) ------->| 第一次:C说"我没数据要发了"
| | S确认,进入CLOSE_WAIT
|<-- ACK (ack=x+1) -------| 第二次:S说"收到,你可以关了"
| | S继续发剩下的数据...
|<-- FIN (seq=y) ---------| 第三次:S说"我也没数据了"
| | S进入LAST_ACK
|---- ACK (ack=y+1) ------>| 第四次:C说"收到"
| | S收到ACK,进入CLOSED
|(TIME_WAIT 等待2MSL) |
|------> CLOSED |
  • 第一次挥手:客户端发 FIN,seq=1001,ack=5001。客户端进入 FIN_WAIT_1 状态,意思是”我没数据要发了,可以关了”。
  • 第二次挥手:服务器回 ACK,ack=1002。服务器进入 CLOSE_WAIT 状态。注意这一步服务器只是确认收到了客户端的 FIN,但服务器自己可能还有没发完的数据,得先把剩下的发完。客户端收到这个 ACK 后进入 FIN_WAIT_2 状态。
  • 第三次挥手:服务器把剩下的数据发完后,也发 FIN,seq=5001。服务器进入 LAST_ACK 状态,意思是”我也没数据了,可以关了”。
  • 第四次挥手:客户端回 ACK,ack=5002。客户端进入 TIME_WAIT 状态,等待 2 个 MSL(最大报文段寿命,Max Segment Lifetime)后才真正关闭。服务器收到这个 ACK 后直接进入 CLOSED 状态。

关于数据传输与关闭的顺序,你的理解基本对——第二次挥手后服务器发剩下的数据,第三次挥手时服务器发 FIN。但要注意,服务器发剩下的数据不是在第二次和第三次之间单独发,而是在收到客户端的 FIN 后、发自己的 FIN 之前这段时间里发。也就是说,服务器在 CLOSE_WAIT 状态时,还可以向客户端发数据,发完了才进入 LAST_ACK 状态并发 FIN。

为什么服务器要把自己的数据发完?客户端都想关闭了不是说明不想要数据了吗?这里要理解 TCP 的全双工特性——客户端说”我不发了”(FIN),但这只代表客户端的发送方向关闭了,客户端还是可以继续接收数据。就像两个人打电话,一方说”我说完了”,但并不代表他不想听对方说,对方还是可以继续说直到说完。所以服务器在收到客户端的 FIN 后,应该把自己这边准备好的数据发完,这样才能保证数据不丢失。

为什么服务器是在第四次挥手(ACK)之后才真正关闭,而不是第三次?因为服务器发完 FIN 后,必须确认客户端收到了这个 FIN,才能放心关闭。如果服务器发完 FIN 就直接关闭,万一这个 FIN 丢了,客户端就永远等不到服务器的 FIN,会一直卡在 FIN_WAIT_2 状态。所以服务器要等客户端的 ACK 确认收到了 FIN,才进入 CLOSED 状态。

为什么是四次不是三次?因为 TCP 是全双工的——双方都能同时发数据,所以两个方向各要单独关闭。建立连接时,服务器的 SYN 和 ACK 可以合并成一个 SYN+ACK 一次发出去;但断开时,服务器收到客户端的 FIN 后可能还有数据没发完,不能立刻发自己的 FIN,所以 ACK 和 FIN 必须分两次发,于是就成了四次。

TIME_WAIT 状态要专门讲一下,这是重点知识。客户端发完最后一个 ACK 后不直接关闭,而是进入 TIME_WAIT,等 2 个 MSL 才真正 CLOSED。为什么?两个理由:一是客户端发的最后一个 ACK 可能丢了,服务器会重传 FIN,客户端得留着状态准备重传 ACK;二是让本次连接的旧报文都在网络里”自然死亡”,2 个 MSL 后旧包都会因为 TTL 到期被丢弃,不会污染下一次新建的连接。所以 TIME_WAIT 是为了可靠性主动做的等待,不是 bug。常见面试题问”为什么服务器端高并发时会有大量 TIME_WAIT?”——其实 TIME_WAIT 通常出现在主动关闭方,服务器如果总是被客户端主动断开,自己这边是 CLOSE_WAIT,反过来如果服务器主动断开才会出现 TIME_WAIT,这个方向别记反。

TCP可靠性机制

TCP 可靠性靠这些机制保证:序号和确认号、重传、流量控制(滑动窗口)、拥塞控制(慢启动、拥塞避免、快重传、快恢复)。

滑动窗口做的是流量控制——发送方不能一股脑把数据全发出去把接收方淹没,得根据接收方的处理能力来。具体过程是这样的:接收方在 ACK 报文里带一个”窗口大小”字段(rwnd,接收窗口),告诉发送方”我还能接收多少字节”。发送方就维护一个发送窗口,窗口大小等于 rwnd,窗口内的数据可以连续发出去不等确认,窗口外的数据必须等收到 ACK 让窗口向前滑动后才能发。

举个例子,假设接收方通告窗口 rwnd=4000 字节,发送方有 6000 字节要发。窗口内的前 4000 字节先连续发出去,剩下 2000 字节得等。接收方收到前 1000 字节、处理完后回 ACK 时把窗口通告更新成 5000(因为它处理掉 1000 字节腾出了空间),发送方窗口向前滑动 1000 字节,又能多发 1000 字节了。如果接收方处理不过来、缓冲区快满了,就会把窗口通告改小,比如改成 500,发送方就发慢点;如果接收方完全处理不过来,会通告窗口=0(零窗口),发送方就停发,定期发零窗口探测包看接收方啥时候缓过来。这就是滑动窗口流量控制——接收方通过窗口大小动态指挥发送方”快一点、慢一点、停下来”。

拥塞控制做的是另一件事——防止网络本身被压垮。滑动窗口管的是”接收方能不能扛得住”,拥塞控制管的是”网络中间的链路和路由器能不能扛得住”。发送方维护一个拥塞窗口 cwnd,实际发送窗口 = min(rwnd, cwnd)。拥塞控制有四个经典阶段:

  • 慢启动:连接刚建立时 cwnd=1(一个 MSS,最大报文段大小),每收到一个 ACK 就 cwnd+1,结果就是每个 RTT(往返时间)窗口翻倍,呈指数增长,1→2→4→8→16……这一阶段叫慢启动不是因为慢,而是初始值小、增长快。一直涨到 ssthresh(慢启动阈值)才换档。

这里要重点解释一下慢启动为什么是指数增长。假设 cwnd=1,发送方发出去 1 个报文段,收到 ACK 后 cwnd 变成 2,这时可以发 2 个报文段,两个都收到 ACK 后 cwnd 变成 4,这时可以发 4 个报文段,四个都收到 ACK 后 cwnd 变成 8……你看,每个 RTT 里,发送方可以多发一倍的报文段,因为每收到一个 ACK 就多一个”发送额度”。比如 cwnd=2 时发了两个报文段,收到两个 ACK,每个 ACK 让 cwnd+1,所以 cwnd 变成 4。这个原理就像你去银行取钱,第一次取 100,银行说”下次可以取 200”,你取了 200,银行说”下次可以取 400”——每次都翻倍,钱越取越多。

  • 拥塞避免:cwnd 到了 ssthresh 之后改成线性增长,每个 RTT 只加 1,1→2→3→4……增长慢下来稳着跑,避免一下子冲爆网络。
  • 快重传:如果发送方连续收到 3 个重复 ACK,说明这个包丢了,立刻重传那个丢失的包,不用等超时计时器到期。
  • 快恢复:快重传后不回到慢启动阶段,而是把 ssthresh 设为当前 cwnd 的一半,cwnd 也设为这个新 ssthresh,然后进入拥塞避免线性增长,不从头开始。

如果是真超时(不是 3 个重复 ACK 踩出来的),那就比较严重了,ssthresh 设为当前 cwnd 的一半,cwnd 直接回到 1,从头开始慢启动。所以”3 个重复 ACK”和”真超时”是两种不同程度的拥塞信号,前者轻、后者重,恢复策略也不一样,这个对比要分清。

TCP vs UDP的应用场景对比

光说”TCP 可靠、UDP 快”还不够具体,得知道哪些应用用哪个、为什么。下面挑几个典型场景,照着”应用对协议的诉求”来配对,配得对就答得对。

TCP 适合”不能丢、必须按序到达”的场景。HTTP 和 HTTPS(网页浏览)——少一个字节网页就显示不正常,必须可靠;FTP(文件传输)——文件传一半错个位就废了;SMTP/POP3/IMAP(邮件)——邮件少一段内容不行;SSH(远程登录)——你打的每个字符都得准确到达,错一个就命令变了。这些应用里,可靠性比实时性重要,所以选 TCP。

UDP 适合”要快、能容忍丢包、要支持一对多”的场景。DNS 查询——就一个小小的请求和响应,建 TCP 连接三次握手太奢侈,UDP 一来一回最干脆。这里要解释一下为什么 UDP 适合 DNS 查询。首先,DNS 查询的数据量很小,通常一个请求和响应加起来也就几十个字节,用 UDP 刚好合适,不需要 TCP 那套复杂的可靠性机制。其次,DNS 查询的超时重传机制本身就能保证可靠性——客户端发一个 UDP 请求,如果没收到响应,等一小会儿就重发,最多重发几次,要是还没收到就判定失败,这个机制比 TCP 的重传简单多了。最后,DNS 查询需要快,用户在浏览器里输入网址,希望立刻就能解析出 IP 地址,要是用 TCP 三次握手再传数据,延迟会明显增加,影响用户体验。所以 UDP 是 DNS 查询的首选。视频直播和语音通话——丢几个包最多花屏或卡顿一下,但延迟一大就完全没法用;网络游戏——同步位置信息要实时,旧的数据到了也没意义宁可丢;DHCP(动态主机分配 IP)——客户端连 IP 都没有,根本没法建 TCP 连接,只能用 UDP。共同点是对实时性要求高、对单包可靠性要求低,所以选 UDP。

常见的对比点还有:DNS 既可以走 UDP 也可以走 TCP,区域传送(zone transfer,整个区域数据同步)用 TCP 因为数据大、要可靠,但普通查询用 UDP;HTTP/3 之前 HTTP 都基于 TCP,HTTP/3 改用了基于 UDP 的 QUIC 协议(HTTP/3 于 2022 年 6 月标准化为 RFC 9114,QUIC 基础协议为 RFC 9000),这是为了减少握手延迟。看到”DNS 一定用 UDP””HTTP 一定用 TCP”这种绝对化表述要警惕。

应用层协议详解

应用层是离用户最近的一层,各种网络应用都在这里。除了 HTTP/HTTPS,还有很多重要协议需要理解。

SFTP与FTP的关系

FTP(文件传输协议)是传统的文件传输协议,它用两条 TCP 连接:一条控制连接(用来发命令,比如 ls、cd),一条数据连接(用来传文件内容)。但 FTP 有个大问题:数据是明文传输的,用户名密码也明文传,非常不安全。

SFTP(SSH File Transfer Protocol)就解决了这个问题。它不是 FTP 的简单升级,而是基于 SSH 的文件传输协议——所有数据都经过 SSH 加密,包括用户名密码和文件内容。你可以把 SFTP 想象成”穿了加密外衣的 FTP”,安全得多。现在主流的文件传输工具(比如 FileZilla)都支持 SFTP,而纯 FTP 已经很少用了。

SMTP、IMAP与邮件协议

SMTP 是邮箱协议吗?是的,它是发送邮件的协议。不管是 Windows 还是 Linux 上的 mail 命令,底层都是用 SMTP 来发邮件的。SMTP 默认端口 25,负责把邮件从你的电脑发到邮件服务器,再从一个邮件服务器转发到另一个邮件服务器。

但 SMTP 只管发不管收,收邮件需要另一个协议。常见的收邮件协议有两个:POP3 和 IMAP。POP3 是把邮件从服务器下载到本地,下载后服务器上就没有了;IMAP 是在服务器上管理邮件,你在本地看到的只是邮件的副本,删邮件、移文件夹都会同步到服务器。现在主流邮箱(比如 Gmail、QQ 邮箱)都支持 IMAP,因为它更方便在多个设备之间同步邮件。

所以完整的邮件流程是:你写好邮件→用 SMTP 发到你的邮件服务器→你的服务器用 SMTP 转发到对方的邮件服务器→对方用 POP3 或 IMAP 从服务器上取邮件。

RPC与现代Agent架构

RPC(远程过程调用)在现代 Agent 工程设计中处于什么定位?你可以把 RPC 想象成”远程的函数调用”——你在本地调一个函数,这个函数实际上是在远程服务器上执行的,对你来说就像调本地函数一样方便。

在 Agent 架构中,RPC 通常用作服务之间的通信方式。比如你的 Agent 需要调用一个大语言模型的 API,这个调用可能就是通过 RPC 实现的;或者你的 Agent 要调用一个数据库服务、一个工具服务,也可以用 RPC。为什么有人说在 RPC 层做 Agent?因为很多服务的接口是用 RPC 定义的,Agent 需要理解这些接口的语义,才能正确调用。比如一个 Agent 要查天气,它需要知道天气服务的 RPC 接口怎么调用、参数是什么、返回值是什么,这就是”在 RPC 层做 Agent”的含义。

SSL/TLS与SSH的关系

SSL 和 TLS 是什么关系?SSL 是早期的安全协议,TLS 是 SSL 的升级版。SSL 2.0、3.0 早已不安全被废弃,现在我们说的 SSL 其实大多是指 TLS 1.2 或 TLS 1.3。你可以把它们想象成”安全协议的新旧版本”,TLS 是更安全的新版本。

SSL/TLS 和 SSH 有关系吗?有关系,但它们是不同的协议。SSL/TLS 主要用于加密网络通信(比如 HTTPS),而 SSH 主要用于远程登录和安全文件传输。不过它们的核心思想是一样的——都是用非对称加密交换对称密钥,然后用对称密钥加密数据。你可以把它们想象成”两种不同用途的加密工具”,SSL/TLS 管网页加密,SSH 管远程操作加密。

DHCP动态主机配置协议

DHCP(动态主机配置协议)负责给局域网内的设备分配 IP 地址。什么是动态分配 IP?就是设备开机后自动从 DHCP 服务器(通常是路由器)获取 IP 地址、子网掩码、网关、DNS 服务器等配置,不用手动设置。这就像你去酒店住,前台自动给你分配一个房间号,不用你自己找。

为什么还需要连接追踪?连接追踪是防火墙和 NAT 设备用来识别和管理网络连接的技术。比如你的电脑通过 NAT 访问外网,NAT 设备需要记录”哪个内网 IP 哪个端口对应哪个外网 IP 哪个端口”,这样才能把服务器的响应正确转发回来。连接追踪就是干这个活的。

这里要澄清一个常见的混淆:Zone Transfer(区域传送)是 DNS 的概念,不是 DHCP 的。DNS 的区域传送是把整个 DNS 区域的数据从一台服务器同步到另一台,因为数据量大、需要可靠传输,所以用 TCP。而 DHCP 本身不涉及区域传送,它用 UDP 是因为客户端一开始连 IP 都没有,根本没法建 TCP 连接,只能用 UDP 广播来发现 DHCP 服务器,而且 DHCP 的数据量很小,一个请求和响应就够了。

HTTP与HTTPS

HTTP 是超文本传输协议,基于 TCP,默认端口 80。它是无状态的(每次请求相互独立,所以才有 Cookie/Session 来维持状态),请求-响应模式。

HTTP与DNS的传输层协议选择

HTTP 和 DNS 到底是用 TCP 还是 UDP?答案是两者皆可,看场景。HTTP 在 HTTP/3 之前都是基于 TCP 的,因为 HTTP 需要可靠传输——一个网页少一个字节都不行。但 HTTP/3 改用了基于 UDP 的 QUIC 协议,这是为了减少握手延迟。

DNS 呢?普通的 DNS 查询用 UDP,因为数据量小、速度快,建 TCP 连接太奢侈。但如果 DNS 响应超过 512 字节(UDP 的默认最大长度),或者是区域传送(把整个 DNS 区域的数据从一台服务器同步到另一台),就会用 TCP,因为需要可靠传输。所以 DNS 是”平时用 UDP,大数据用 TCP”。

HTTP报文结构

HTTP 报文的结构像一封信,分四部分:请求行或状态行、头部、空行、主体。咱们先画个图看清楚:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
请求报文:
-------------------
GET /users?id=123 HTTP/1.1 <- 请求行(方法 路径 版本)
Host: example.com <- 头部(键值对)
User-Agent: Chrome/91.0
Content-Type: application/json

{"name":"张三"} <- 主体(实际数据)
-------------------

响应报文:
-------------------
HTTP/1.1 200 OK <- 状态行(版本 状态码 消息)
Content-Type: text/html
Content-Length: 100

<html>...</html> <- 主体(返回的内容)
-------------------

举几个例子。GET 请求查用户信息,参数拼在 URL 里:

1
2
GET /users?id=123&name=张三 HTTP/1.1
Host: example.com

POST 请求提交表单,数据放在 body 里:

1
2
3
4
5
6
POST /users HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 27

name=张三&age=25&email=zhangsan@example.com

POST 请求提交 JSON 数据:

1
2
3
4
5
6
POST /users HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 30

{"name":"张三","age":25,"email":"zhangsan@example.com"}

服务器返回图片:

1
2
3
4
5
HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Length: 102400

[二进制图片数据...]

服务器返回文件:

1
2
3
4
5
6
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Length: 512000
Content-Disposition: attachment; filename="report.pdf"

[二进制PDF数据...]

GET与POST参数格式详解

GET 请求参数拼在 URL 中是怎么拼的?规则很简单:在 URL 后面加一个问号,然后用键值对的形式写参数,多个参数之间用&分隔。比如 http://example.com/users?id=123&name=张三,这里 id=123 和 name=张三 是两个参数。注意中文需要 URL 编码,比如”张三”会被编码成”%E5%BC%A0%E4%B8%89”。

POST 请求的 body 中表单怎么放?要看 Content-Type。如果是 application/x-www-form-urlencoded(默认),格式和 GET 参数一样,比如 name=张三&age=25;如果是 multipart/form-data(上传文件时用),会用分隔符把不同字段分开,每个字段有自己的 Content-Type;如果是 application/json,就直接放 JSON 字符串。

Cookie与认证的关系

Cookie 与什么有关?与状态管理和认证有关。HTTP 是无状态的,服务器记不住你是谁,Cookie 就是用来帮服务器”记住”你的。服务器通过响应头里的 Set-Cookie 字段把 Cookie 写到浏览器里,浏览器之后每次请求都会自动带上这个 Cookie。

Cookie 和 Authentication(认证)是什么关系?认证是确认你是谁的过程,Cookie 是传递认证信息的载体。比如你登录后,服务器生成一个 Session ID,通过 Set-Cookie 发给浏览器,浏览器下次请求带上这个 Cookie,服务器就能通过 Session ID 找到你的登录信息,确认你是已认证用户。所以 Cookie 常用来传递认证凭证,但它本身不是认证机制——认证可以用 Cookie,也可以用 Token(放在请求头里)。

HTTP方法的幂等性

HTTP 方法要记:GET(获取资源,幂等、无副作用)、POST(提交数据、创建资源,非幂等)、PUT(更新/替换资源,幂等)、DELETE(删除资源,幂等)。幂等性是指多次执行结果相同,这个概念要重点掌握。

为什么 GET 幂等而 POST 不幂等,光记结论容易忘,咱们看具体例子就明白了。幂等的意思是”同一个请求执行一次和执行多次,对资源状态的影响是一样的”。

GET 的例子:你访问 http://example.com/users/123,第一次拿到用户 123 的资料,再调十次还是拿到同样的资料,服务器上的数据一点没变——这就是幂等,GET 只是读,不改数据。所以浏览器可以放心地缓存 GET 请求、可以刷新重发、可以从历史记录里重新打开,都不会改变服务器状态。

POST 的例子:你向 http://example.com/users 提交一个表单创建新用户,第一次调用创建了一个 ID=1 的用户,再调一次又创建了一个 ID=2 的用户,调十次就建十个用户——服务器状态每次都变了,所以 POST 不幂等。这就是为什么浏览器在 POST 表单后弹”确认重新提交表单”——防止你手滑点了又点创建了一堆重复数据。

PUT 的例子:你向 http://example.com/users/123 PUT 一份数据”名字=张三”,第一次调用把用户 123 的名字改成张三,再调一次还是张三——服务器状态最终都一样,所以 PUT 幂等。PUT 是”幂等的更新”,因为它把整个资源替换成指定状态,不管调多少次结果都是那个状态。

DELETE 的例子:你 DELETE http://example.com/users/123,第一次调用删掉了用户 123,再调一次用户 123 已经不存在了,但服务器状态没变(还是”用户 123 不存在”),所以 DELETE 也算幂等。

一句话总结:GET、PUT、DELETE 幂等,POST 不幂等。常见问题会问”哪些 HTTP 方法是幂等的”,记住这三个就行。

这里再重新解释一下幂等性,确保你理解透。幂等性的核心是”多次执行对服务器无改变影响”——不管你执行一次还是执行一百次,服务器上的资源状态都是一样的。举个生活中的例子:你去ATM机查余额(GET),查一次和查一百次,你的账户余额都不会变,这就是幂等;你去ATM机存钱(POST),存一次余额多100,存两次余额多200,每次都变,这就是非幂等。再举个例子:你把台灯的开关拨到”开”的位置(PUT),拨一次是开,拨一百次还是开,这是幂等;你按一下台灯的调光按钮(POST),按一次亮度变一点,按一百次亮度差很多,这是非幂等。

HTTP状态码记忆方法

HTTP 状态码太多了,有没有好的记忆方法?有的,记住两位数字加一句话就行。

第一位数字代表类别:

  • 1xx:信息,服务器收到请求了,继续处理
  • 2xx:成功,请求处理完了
  • 3xx:重定向,去别的地方找
  • 4xx:客户端错,你发的请求有问题
  • 5xx:服务器错,我这边出问题了

第二位数字记几个关键的:

  • 200:OK,成功
  • 201:Created,创建成功
  • 301:永久重定向
  • 302:临时重定向
  • 304:没改过,用缓存
  • 400:请求格式错
  • 401:没登录
  • 403:登录了但没权限
  • 404:找不到
  • 500:服务器代码错
  • 502:网关错
  • 503:服务忙
  • 504:网关超时

记的时候可以编个口诀:”一信息二成功,三跳转四错误,五服务器出问题”,再把上面那几个常用的单独记一下,面试时基本够用了。

HTTP状态码详解

HTTP 状态码分五类,记住第一位代表什么:1xx 信息、2xx 成功(200 OK、201 Created)、3xx 重定向(301 永久重定向、302 临时重定向、304 Not Modified 缓存)、4xx 客户端错误(400 请求语法错、401 未认证、403 禁止访问、404 找不到)、5xx 服务器错误(500 内部错误、502 网关错误、503 服务不可用、504 网关超时)。

401 和 403 的区别必须分清,这是重点知识。

401 Unauthorized(未认证)意思是”你是谁我还不知道”。具体场景:你访问一个需要登录的页面,但还没登录,服务器回 401,浏览器看到 401 通常会弹出登录框让你输入账号密码。比如你访问 http://example.com/profile,服务器回 401,意思是”先告诉我你是谁”,你登录后再访问,这次请求带了认证信息(Cookie 或 Token),服务器就放行了。所以 401 的本质是”身份没验证”,需要你证明你是谁。

403 Forbidden(禁止访问)意思是”我知道你是谁,但你没权限”。具体场景:你登录了一个普通用户账号,想访问 http://example.com/admin 后台管理页面,服务器知道你是张三(认证通过了),但张三不是管理员,于是回 403。这时你再怎么登录都没用,因为身份对了但权限不够,得管理员把你升级成管理员角色才能访问。

所以 401 是”没登录或登录信息无效”,403 是”登录了但权限不够”。看到”403 是没认证”这种说法是错的,403 是认证过了但被禁止。再补一个常见点 404,它是 Not Found,意思是”服务器上根本没有这个资源”,跟权限无关,是资源本身不存在,比如你访问了一个写错的 URL。这三个码——401、403、404——是 4xx 客户端错误里最常见的,一定分清。

3xx 重定向里 301 和 302 也常见:301 是永久重定向,搜索引擎会更新索引到新地址,适合域名永久搬迁;302 是临时重定向,搜索引擎保留原地址索引,适合临时跳转。304 Not Modified 是配合缓存用的,客户端问了”这个资源自上次以来变过吗”,没变服务器就回 304 让客户端继续用本地缓存,省了重新下载。这个 304 下面讲缓存时还会详细说。

5xx 服务器错误里 500、502、503、504 的区别也容易混:500 是服务器内部代码出错了;502 是网关错误,反向代理服务器从上游服务器拿到的是错误响应;503 是服务暂时不可用,通常是过载或维护;504 是网关超时,反向代理服务器等上游响应等超时了。

HTTP缓存机制

HTTP 缓存能让网页飞起来,第二次访问一个网站之所以快,就是因为缓存省去了重复下载。浏览器缓存分两类:强缓存和协商缓存,理解了它俩的分工你就理解了整个缓存机制。

强缓存的意思是浏览器根本不向服务器发请求,直接读本地缓存。它靠两个字段控制:一个是 Expires,写一个绝对过期时间,比如”2026 年 12 月 31 日 23:59:59 之前都算有效”,这是 HTTP/1.0 的字段,依赖客户端本机时间,万一本机时间不准就会判断错;另一个是 Cache-Control: max-age=3600,写一个相对过期时间,意思是”从服务器返回算起 3600 秒内有效”,这是 HTTP/1.1 的字段,更精准,所以现在以 Cache-Control 为准。强缓存命中时浏览器显示 200 from cache,根本不打扰服务器,是最快的一种。

协商缓存的意思是强缓存过期了,浏览器去问一下服务器”这个资源自上次以来变过吗”,没变就用旧的。它靠两对字段:第一对是 Last-Modified 和 If-Modified-Since,服务器第一次返回资源时带上 Last-Modified 表示最后修改时间,浏览器下次请求时带上 If-Modified-Since 把这个时间还回去,服务器比较后没变就回 304;第二对是 ETag 和 If-None-Match,服务器第一次返回资源时带上 ETag(资源的唯一标识,类似哈希值),浏览器下次请求时带上 If-None-Match 把这个标识还回去,服务器比较后没变就回 304。ETag 比 Last-Modified 更精确,因为有些文件修改了内容没变(比如重新保存但内容相同),Last-Modified 会误判为已修改,而 ETag 基于内容计算就能识别出来。

完整的缓存流程是这样的:浏览器请求一个资源时,先检查强缓存,如果还在有效期内(没过期),直接用本地缓存,状态码显示 200 from cache,根本不打扰服务器;如果强缓存过期了,浏览器就带上协商缓存标识(If-Modified-Since 或 If-None-Match)去问服务器,服务器判断资源没改过就回 304,浏览器继续用本地缓存;如果改过了,服务器就回 200 并返回新资源,浏览器拿到新资源更新缓存。所以 304 就是协商缓存命中的标志,前面状态码里提到的 304 现在你就明白它的来历了。

HTTPS握手详细过程

HTTPS = HTTP + SSL/TLS 加密,默认端口 443。它解决的是 HTTP 明文传输不安全的问题,提供加密(防窃听)、身份认证(防冒充,靠证书)、完整性校验(防篡改)。

HTTPS 握手的核心思想是”用非对称加密安全交换一个对称密钥,之后用对称密钥加密实际数据”。为什么要这样混着用?因为非对称加密慢、对称加密快——非对称加密适合加密小数据(比如密钥本身),对称加密适合加密大数据(比如网页内容)。所以协议设计成:先用慢的非对称加密把对称密钥安全传过去,之后所有的通信都切换到快的对称加密。

具体步骤走一遍:

  • 第一步:客户端发 ClientHello,告诉服务器自己支持的 SSL/TLS 版本、支持的加密套件列表(比如 RSA+AES、ECDHE+AES 等)、一个客户端生成的随机数(叫 client_random)。
  • 第二步:服务器发 ServerHello,选定一个 SSL/TLS 版本、选定一个加密套件、返回一个服务器生成的随机数(叫 server_random),并把服务器的数字证书发给客户端。证书里包含服务器的公钥,由 CA(证书颁发机构)用私钥签名。
  • 第三步:客户端验证证书合法性。验证内容包括:证书是不是受信任的 CA 签发的(用操作系统/浏览器内置的 CA 公钥验签)、证书是否在有效期内、证书里的域名和当前访问的域名是否一致、证书是否被吊销(查 CRL 或 OCSP)。任何一项不过就报警。
  • 第四步:客户端生成第三个随机数,叫 pre_master_secret(预主密钥),用服务器证书里的公钥加密后发回服务器。这一步是关键——pre_master_secret 用非对称加密传过去,只有持有私钥的服务器能解开,中间人就算截获也解不开。
  • 第五步:服务器用自己的私钥解密得到 pre_master_secret。现在双方手里都有三个数:client_random、server_random、pre_master_secret。双方用同样的算法基于这三个数算出相同的对称会话密钥(master_secret,再派生出加密密钥和 MAC 密钥)。
  • 第六步:客户端发 Change Cipher Spec(告诉服务器”之后用对称加密了”)和 Finished(用协商好的密钥加密的第一条消息,让对方验证密钥协商成功)。
  • 第七步:服务器也回 Change Cipher Spec 和 Finished。
  • 第八步:握手完成。之后客户端和服务器之间所有的 HTTP 通信都用对称密钥加密。

你看,整个过程的核心就是”用非对称加密把 pre_master_secret 安全送到服务器,然后双方用三个随机数算出对称密钥”。为什么需要三个随机数?因为单个随机数可能被预测或重放,三个随机数组合后密钥的不可预测性大幅增强,安全性更高。

关于 CA 证书还要知道一点:CA 是受信任的第三方,它用自己的私钥给服务器的公钥签名,客户端用 CA 的公钥(系统内置)验签。如果验签通过,说明这个公钥确实是这个服务器自己的、没被中间人掉包。这就是 HTTPS 防止中间人攻击的核心机制——中间人就算能截获通信,也伪造不出 CA 的签名。

注意 SSL/TLS 的版本演进也要大概知道:SSL 2.0、3.0 早已不安全被废弃,TLS 1.0、1.1 也基本停用,目前主流是 TLS 1.2 和 TLS 1.3(TLS 1.3 于 2018 年 8 月发布为 RFC 8446)。TLS 1.3 大幅简化了握手过程,把往返次数减少到 1-RTT,甚至支持 0-RTT 恢复,进一步降低延迟。

HTTP协议的演进

HTTP 协议本身也在不断演进,了解版本差异能帮你理解为什么现代网页这么快。

HTTP/1.0 时代,每次请求都要新建一个 TCP 连接,请求完就断开,开销很大。HTTP/1.1 引入了持久连接(Keep-Alive),一个 TCP 连接可以连续发多个请求,省去了反复握手挥手的开销;还引入了管道化,允许浏览器在一个连接上连续发多个请求不等响应。但管道化有个问题叫”队头阻塞”——服务器必须按请求顺序返回响应,前面一个慢了后面的都得等着,所以实际中浏览器很少真的用管道化,而是开多个 TCP 连接并行请求。

HTTP/2 解决了队头阻塞问题。它把数据分成一个个帧(frame),每个帧打上流 ID(stream id),属于不同请求的帧可以在同一个 TCP 连接上交叉发送,这就是”多路复用”——一个 TCP 连接上同时跑多个请求和响应,互不阻塞。它还支持头部压缩(用 HPACK 算法减少重复头部的传输,因为 HTTP 头部里很多字段每次请求都重复)和服务器推送(服务器主动把资源推给客户端,比如 HTML 里引用的 CSS,不用等浏览器请求)。HTTP/2 让一个连接扛住大量并发请求成为可能,是现代网页性能提升的关键。

HTTP/3 更激进,干脆不用 TCP 了,改用基于 UDP 的 QUIC 协议(HTTP/3 于 2022 年 6 月标准化为 RFC 9114,QUIC 基础协议为 RFC 9000)。为什么?因为 TCP 是内核实现的,握手要 1 个 RTT,TLS 握手又要 1 到 2 个 RTT,加起来延迟不小;而且 TCP 有队头阻塞——一个包丢了,整个连接上后续的包都得等它重传。QUIC 把传输层和加密层合并到一起,握手只要 1 个 RTT 甚至 0 RTT(恢复连接时),而且丢包只阻塞当前流不影响其他流,还支持”连接迁移”——你从 Wi-Fi 切到 4G,连接不会断,因为 QUIC 用连接 ID 而不是 IP 加端口来标识连接。HTTP/3 是 Google 主推的,YouTube 等大站已经在用。

DNS:域名系统的电话本

人记不住 IP 地址(比如 142.250.185.46),但容易记住域名(比如 www.baidu.com)。DNS(域名系统)就是用来把域名翻译成 IP 地址的,相当于互联网的电话本。前面讲过 DNS 是应用层协议、查询通常走 UDP,现在咱们把一次完整的解析过程走一遍。

域名解析的过程是层层递进的询问。假设你在浏览器输入 www.example.com,浏览器要拿到这个域名对应的 IP 才能发请求,它会按这个顺序找。

第一步,浏览器先查自己的 DNS 缓存。浏览器会缓存最近访问过的域名对应的 IP,Chrome 里可以通过 chrome://net-internals/#dns 查看。如果缓存里有且没过期,直接用,查询到此结束。

第二步,浏览器缓存没有,就去问操作系统。操作系统也有自己的 DNS 缓存和 hosts 文件,Windows 用 ipconfig /displaydns 查看,Linux 用 systemd-resolve –statistics 查看。hosts 文件是一个本地的静态映射表,你可以手动写”127.0.0.1 localhost”这样的记录,系统会优先信 hosts 文件,所以开发时常用它来把某个域名指向本地做测试。

第三步,操作系统也没有,就向配置的本地 DNS 服务器发起查询。本地 DNS 服务器通常是你 ISP(运营商)提供的,比如电信的 114.114.114.114 或者 Google 的 8.8.8.8。你在路由器的 DHCP 配置里看到的那个 DNS 地址就是它。

第四步是本地 DNS 服务器去外面的世界找答案,这里有两种查询模式要分清:递归查询和迭代查询。递归查询是”你替我去问到底”——本地 DNS 服务器替客户端去问其他服务器,一路问到拿到最终结果再返回给客户端,就像你问朋友一个问题,他不会,但他去请教别人,最后把答案告诉你。迭代查询是”你告诉我下一步该问谁”——本地 DNS 服务器告诉客户端下一级 DNS 服务器的地址,让客户端自己去问,就像朋友告诉你”这个问题你得问张三,张三的地址是……”。实际中,客户端到本地 DNS 服务器这一段是递归查询(你把活儿全权委托给本地 DNS 服务器),本地 DNS 服务器到外面那一段是迭代查询(它一级一级往下问)。

第五步,本地 DNS 服务器开始迭代查询的链路:先问根 DNS 服务器(全球共 13 组根 DNS,管理顶级域),根 DNS 说”我不知道 www.example.com 的 IP,但我知道负责 .com 的顶级域 DNS 在哪,你去问它”;本地 DNS 服务器再去问顶级域 DNS(负责 .com),顶级域 DNS 说”我不知道 www.example.com 的 IP,但我知道 example.com 这个域的权威 DNS 在哪,你去问它”;本地 DNS 服务器最后去问权威 DNS(example.com 自己的 DNS 服务器),权威 DNS 才是真正知道 www.example.com 对应哪个 IP 的,它返回 IP,本地 DNS 服务器拿到后缓存一份,再返回给客户端。客户端拿到 IP 后也能缓存一份,下次直接用。

你看,整个解析过程就是”层层下问”:从浏览器缓存问到操作系统缓存,再到本地 DNS 服务器,再到根、顶级域、权威 DNS,一级一级往下钻,直到拿到最终的 IP。每一级都可能缓存结果,所以第二次访问同一个域名通常很快。

DNS 还能做负载均衡。大型网站(比如百度)通常把同一个域名对应多个 IP 地址,DNS 服务器在解析时用轮询或者其他策略返回不同的 IP,把流量分发到多台服务器上,避免某一台过载。这就是 DNS 负载均衡——简单粗暴,但在地理分布的流量调度上很有效,比如把北京用户的请求解析到北京机房的 IP,把上海用户的请求解析到上海机房的 IP,靠的就是 DNS 的智能调度。

IP地址与子网划分

IP地址分类与快速判断

IPv4 按网络号位数分类。A 类:第一位 0,范围 1.0.0.0 到 126.255.255.255,默认掩码 /8,127 是环回地址。B 类:前两位 10,范围 128.0.0.0 到 191.255.255.255,默认掩码 /16。C 类:前三位 110,范围 192.0.0.0 到 223.255.255.255,默认掩码 /24。D 类组播(224 到 239),E 类保留(240 到 255)。

如何快速判断一个 IP 属于哪一类?不用记二进制前缀,记 IP 第一段的十进制范围就够了。看 IP 地址第一个点之前的那个数字:

  • 1 到 126:A 类。比如 10.0.0.1 是 A 类(其实它是 A 类私有地址)。
  • 127:环回地址,不算 A/B/C 任何一类,专门给本机测试用,ping 127.0.0.1 就是 ping 自己。
  • 128 到 191:B 类。比如 172.16.0.1 是 B 类(其实它是 B 类私有地址)。
  • 192 到 223:C 类。比如 192.168.1.1 是 C 类(其实它是 C 类私有地址)。
  • 224 到 239:D 类组播,单播通信不用。
  • 240 到 255:E 类保留。

判断口诀就是”看第一段数字落在哪个区间”。比如题目给你一个 200.1.2.3,你看 200 落在 192-223,立刻判断是 C 类,默认掩码 /24。给你 130.5.6.7,130 落在 128-191,是 B 类,默认掩码 /16。这个判断几乎是常识题,但要快、要准,别犹豫。

子网划分完整计算示例

子网划分是计算重点。掩码把 IP 分成”网络位 + 主机位”,借主机位做子网位就能把一个大网切成多个小网。计算套路:给定 IP 和掩码位数 n,网络地址 = IP 与子网掩码按位与;广播地址 = 网络地址的主机位全置 1;可用主机范围 = 网络地址 +1 到 广播地址 -1;可用主机数 = 2 的(32-n)次方减 2(去掉网络号和广播)。CIDR(无类别域间路由)就是用 /n 表示掩码位数,不再死守 A/B/C 分类。NAT(网络地址转换)让内网多台机器共用一个公网 IP 出网。

光记公式不够,咱们拿一道完整题算一遍,你照着这个步骤走,任何子网题都能解。

题目:给定 IP 192.168.1.100/26,求网络地址、广播地址、可用主机范围、可用主机数。

第一步,理解 /26 的含义。26 表示 IP 的前 26 位是网络位,剩下 32-26=6 位是主机位。子网掩码是 26 个连续的 1,写成十进制是 255.255.255.192——前三个 8 位全 1(255),最后 8 位是 11000000(即 192)。

第二步,把 IP 写成二进制按位与掩码算网络地址。IP 192.168.1.100 的最后一字节 100 写成二进制是 01100100;掩码最后一字节 192 是 11000000。按位与:01100100 & 11000000 = 01000000,也就是十进制 64。所以网络地址是 192.168.1.64。这一步用 Python 表示就是:

1
2
3
4
5
# 计算网络地址:IP 和掩码按位与
ip_last = 100 # 192.168.1.100 的最后一字节
mask_last = 192 # /26 掩码的最后一字节
network_last = ip_last & mask_last
print(network_last) # 输出 64,所以网络地址是 192.168.1.64

第三步,算广播地址。广播地址 = 网络地址的主机位(后 6 位)全置 1。网络地址 192.168.1.64 的最后一字节 64 是 01000000,把后 6 位全置 1 得 01111111,也就是十进制 127。所以广播地址是 192.168.1.127。

第四步,算可用主机范围。可用主机从”网络地址 +1”到”广播地址 -1”,所以是 192.168.1.65 到 192.168.1.126。

第五步,算可用主机数。主机位有 6 位,所以主机位组合数是 2^6=64,去掉网络号(全 0,对应 192.168.1.64)和广播地址(全 1,对应 192.168.1.127),可用主机数 = 64 - 2 = 62 台。

总结一下这道题的答案:网络地址 192.168.1.64、广播地址 192.168.1.127、可用主机范围 192.168.1.65 ~ 192.168.1.126、可用主机数 62 台。整个计算套路就是这五步,再复杂的题也是这个流程,只是数字变一变。

再多走一个例子帮你巩固:给定 IP 10.10.100.200/20,求网络地址。

  • 掩码 /20 表示前 20 位网络位,掩码前两字节是 255.255,第三字节是 11110000(即 240),第四字节是 0。所以掩码是 255.255.240.0。
  • IP 第三字节 100 = 01100100,掩码第三字节 240 = 11110000,按位与 = 01100000 = 96。
  • 网络地址 = 10.10.96.0。

你看,套路一致,只是把”算第几个字节”换了一下。/26 之类的非整 8 的掩码,核心就是看它落在第几个字节,只在那个字节做按位与,其他字节要么照抄(在掩码为 255 的字节)要么置 0(在掩码为 0 的字节)。

私有IP地址与NAT

私有 IP 地址范围(不能在公网路由,用于内网)必背:10.0.0.0/8、172.16.0.0/12、192.168.0.0/16。特殊地址:127.0.0.0/8 环回、0.0.0.0 本机所有地址、255.255.255.255 广播、169.254.0.0/16 自动私有地址(DHCP 拿不到地址时分配)。

为什么要专门留出私有 IP 地址段?因为 IPv4 地址总共只有约 43 亿个,地球上设备多得多,根本不够分。所以 IANA(互联网号码分配机构)留了三段私有地址给内网用:A 类留了 10.0.0.0/8(1600 多万个地址,大企业用),B 类留了 172.16.0.0/12(约 100 万个,中型网络用),C 类留了 192.168.0.0/16(约 6.5 万个,家庭和小公司用)。这些地址只能在局域网内部用,公网路由器看到这些地址的包直接丢弃,所以全世界的内网都能重复用同一批私有地址而不冲突——你家路由器是 192.168.1.1,我家也是,没关系,反正它们不出公网。

但内网的机器要访问公网怎么办?这时候 NAT(网络地址转换)就登场了。NAT 让内网多台机器共用一个公网 IP 出网。工作过程:

  • 第一步:内网机器 192.168.1.10:54321 发起一个到公网服务器 8.8.8.8:80 的请求,包先到家里的 NAT 路由器。
  • 第二步:路由器把这个包的源地址 192.168.1.10:54321 改成自己的公网地址,比如 1.2.3.4:60000(端口也换成一个空闲的高位端口),并把”192.168.1.10:54321 ↔ 1.2.3.4:60000”这条映射记在自己的 NAT 表里。
  • 第三步:包带着伪装的源地址 1.2.3.4:60000 出去,到达 8.8.8.8:80。服务器以为是 1.2.3.4:60000 在跟它说话,根本不知道后面其实藏着一个 192.168.1.10。
  • 第四步:服务器回包给 1.2.3.4:60000,路由器收到,查 NAT 表发现这条映射对应内网的 192.168.1.10:54321,于是把目的地址改回来转发给内网机器。

这就是 NAT 的核心:靠端口号区分”这个公网 IP 后面到底藏着哪台内网机器”,所以这种叫 NAPT(网络地址端口转换)更准确。一个公网 IP 理论上靠 65535 个端口能给几万台内网机器同时用,极大缓解了 IPv4 地址不够的问题。NAT 的副作用是破坏了端到端的直接通信——服务器没法主动发起连接到内网机器(因为 NAT 表里没有对应映射),所以 P2P 应用、内网穿透要专门处理。另外 NAT 还要改端口号,所以传输层的端口在 NAT 这一层被动了手脚,这也是为什么 NAT 通常被视为网络层和传输层之间的功能。

网络安全与状态管理

讲网络绕不开安全和状态。HTTP 本身是无状态的,但 Web 应用需要”记住”用户是谁、登录了没、购物车里有什么。怎么在无状态的协议上维持状态、又怎么保证状态不被恶意利用,就是这一节要讲的事。

同源策略与跨域CORS

同源策略是浏览器最基本的安全防线。它的意思是:协议、域名、端口三者必须完全相同,浏览器才允许一个页面访问另一个页面的 Cookie、DOM 等资源。比如 http://a.com 的页面想读 https://a.com 的 Cookie,协议不同,浏览器拦;http://a.com 想读 http://b.com 的 DOM,域名不同,浏览器拦;http://a.com:3000 想访问 http://a.com:8080 的接口,端口不同,浏览器也拦。这是为了防止恶意网站窃取你在其他网站的登录态和数据——如果没有同源策略,你打开一个钓鱼网站,它就能读到你刚登录过的银行网站的 Cookie,钱就没了。

但现代开发里前后端分离是常态,前端跑在 http://localhost:3000,后端跑在 http://localhost:8080,这本身就构成了跨域。浏览器会拦跨域请求,除非后端通过 CORS(跨源资源共享)明确允许。CORS 是服务器通过响应头告诉浏览器”我同意这个来源访问我”的机制。

CORS 把请求分两类:简单请求和预检请求。简单请求要同时满足几个条件——方法是 GET、HEAD 或 POST,且 Content-Type 只能是 application/x-www-form-urlencoded、multipart/form-data 或 text/plain 这三种之一,且不设置自定义头部。满足这些条件的请求,浏览器直接发出去,然后检查响应头里的 Access-Control-Allow-Origin 字段是否允许当前来源,允许就放行,不允许就拦截。预检请求针对的是不满足上述条件的请求(比如 PUT、DELETE 方法,或者 Content-Type 是 application/json,或者带自定义头部),浏览器会先发一个 OPTIONS 请求问服务器”我能不能用这个方法、带这个头部来访问你”,服务器回”可以”,浏览器才发真正的请求。这个 OPTIONS 请求就是”预检”,相当于先敲门问能不能进,得到允许才正式进。

HTTP 是无状态的,但 Web 应用要”记住”用户登录了没、购物车里有什么。Cookie 和 Session 就是用来补这个缺的。

Cookie 是存在客户端的小块数据。服务器通过响应头里的 Set-Cookie 字段把 Cookie 写到浏览器里,浏览器之后每次请求同一个域都会自动带上 Cookie。Cookie 适合存一些不大的、客户端能读的信息,比如用户偏好设置、登录态的 Session ID。

Session 是存在服务器端的用户状态数据。客户端登录后,服务器创建一个 Session 对象存用户信息,给这个 Session 分配一个唯一的 Session ID,把这个 ID 通过 Cookie 发给浏览器。浏览器下次请求自动带上这个 Cookie,服务器读出 Session ID 找到对应的 Session,就知道这个请求是谁发的。Session 适合存敏感的、不能让客户端篡改的信息,比如用户角色、权限。

两者的核心区别就是存的位置:Cookie 在客户端,Session 在服务器端。Session 通常通过 Cookie 里的 Session ID 来关联客户端,但 Cookie 也可以独立用来存非敏感信息。一般实践中,登录态用 Session 存(安全),Session ID 通过 Cookie 传(方便)。

单台服务器时这套机制没问题,但网站一旦上了多台服务器做负载均衡,问题就来了:用户第一次请求被分到 A 服务器,A 创建了 Session;第二次请求被分到 B 服务器,B 没有这个 Session,用户就被踢出登录了。怎么在多台服务器之间共享 Session?有三种常见方案。

第一种是 Session 复制:服务器之间互相同步 Session 数据,每台都存全量。优点是简单,缺点是服务器多了之后同步开销大、有延迟,不适合大规模集群。

第二种是集中式存储:把所有 Session 存到一个共享存储里,比如 Redis,所有服务器都去这个共享存储读写。这是最常用的方案,Redis 本身性能高、支持过期时间,很适合做 Session 存储。

第三种是 Token(比如 JWT,JSON Web Token):彻底放弃服务器端 Session,改成把用户信息加密后生成一个 Token 发给客户端,客户端每次请求在请求头里带上 Token,服务器拿到 Token 验证签名通过就认。这种方案是”无状态”的——服务器不存任何会话信息,所以天然支持分布式,加机器不用迁移 Session。缺点是 Token 一旦签发在过期前没法主动让它失效(除非维护一个黑名单),而且 Token 里塞的信息多的话体积会比 Session ID 大。

其他重要概念

WebSocket

HTTP 是请求-响应模型,客户端不主动问,服务器不会主动答,所以做不了实时推送。WebSocket 就是为实时通信设计的,它提供全双工通道——客户端和服务器可以同时向对方发数据,像打电话一样,谁想说话谁就说,不用等对方问。

WebSocket 的建立过程挺巧妙:它先借 HTTP 的壳。客户端发一个 HTTP 请求,但带上 Upgrade: websocket 头,意思是”我想升级协议”;服务器同意就回 101 Switching Protocols,连接就从 HTTP 切换成 WebSocket 了。握手成功之后,这条连接就不再走 HTTP 协议,而是走 WebSocket 自己的二进制分帧协议。所以 WebSocket 和 HTTP 的关系是”借 HTTP 完成握手,握手后单飞”。

WebSocket 的典型应用场景是在线聊天、实时游戏、股票行情推送、协同编辑(比如多人同时改一份文档)。这些场景的共同点是对实时性要求高,服务器需要主动推数据而不是等客户端问。除了 WebSocket,还有 Server-Sent Events(SSE)做服务器单向推送、HTTP/2 的服务器推送用于推资源(不是全双工),但能做到双向实时通信的主流方案就是 WebSocket。

CDN

CDN(内容分发网络)解决的是”用户离服务器太远导致访问慢”的问题。它的思路是在全球各地部署很多节点服务器,把网站的静态资源(图片、CSS、JS)缓存到这些节点上。用户访问时,CDN 智能调度让用户去离他最近的节点取资源,缩短了传输距离,自然就快了。好比一家全国连锁的快递公司在每个城市都建仓库,用户从最近的仓库取货,不用都从总部发货。

CDN 的好处有三个:一是降低延迟,用户就近取资源,响应快;二是减轻源站压力,大部分请求被 CDN 节点挡掉了,源服务器不用扛全部流量;三是能抵御部分 DDoS 攻击,攻击流量被 CDN 节点分散吸收,不会全部打到源站。个人博客也常用 CDN 加速图片和样式文件,提升访问速度。

负载均衡

当一台服务器扛不住全部流量时,就得多台服务器分担,怎么把请求合理地分发到多台服务器上,就是负载均衡做的事。负载均衡分两层:四层和七层。

四层负载均衡(比如 LVS)工作在传输层,只看 IP 和端口来转发请求,效率高,但不关心应用层内容。它就像快递分拣只看地址不看包裹里是什么。七层负载均衡(比如 Nginx)工作在应用层,能基于 HTTP、HTTPS 等协议做决策,可以处理 SSL 卸载、URL 路由、缓存等,更灵活但开销也更大。它就像分拣员不仅看地址还看包裹内容来决定怎么送。实际中常用组合是四层做入口分发、七层做应用层路由。

负载均衡的常见算法有三个。轮询是最简单的,按顺序一台一台轮流分配请求,公平但不考虑服务器负载差异。最少连接是把请求分给当前连接数最少的那台,比较智能,能避开忙的机器。IP 哈希是根据客户端 IP 算一个哈希值,保证同一个 IP 的请求总发给同一台服务器,这样能保持会话——用户第一次访问落到 A 服务器,之后还是 A 服务器,Session 不会丢。但 IP 哈希的问题是如果某段 IP 流量特别大,会导致负载不均。

RESTful API设计原则

REST(表述性状态转移)是一套 API 设计风格,RESTful API 就是按这套风格设计的接口。它的核心原则有三条。

第一条,用 URL 表示资源。资源是名词,URL 应该指向”东西”而不是”动作”。比如 /users/123 表示用户 123 这个资源,/users/123/orders 表示这个用户的订单列表。不该把动作写进 URL,比如 /getUser?id=123 或者 /deleteUser?id=123 就不 RESTful,因为它们把”做什么”也塞进了 URL。

第二条,用 HTTP 方法表示对资源的操作。GET 表示获取(读),POST 表示创建(新增),PUT 表示更新(整体替换),DELETE 表示删除。这样 URL 只描述”是什么”,方法描述”做什么”,分工清晰。配合状态码返回结果:200 成功、201 创建成功、404 资源不存在、400 请求格式错等。

第三条,无状态。每个请求必须包含服务器处理它所需的全部信息,服务器不保存客户端的会话状态。这意味着任何请求都可以发给任何一台服务器,结果都一样,天然适合分布式。这一条和上面讲的 Token 方案是配套的——Token 把状态存在客户端,服务器无状态,正是 RESTful 的体现。

计算机网络知识速记

OSI 七层从下到上”物数网传会表应”,对应的设备依次是中继器/集线器、交换机/网桥、路由器、网关/防火墙——交换机和路由器最容易记混,交换机工作在数据链路层靠 MAC 地址转发,路由器工作在网络层靠 IP 地址转发。数据封装的”加头加头加头”过程要会,发送方从上到下加,接收方从下到上剥,一层对应一层。TCP/IP 四层模型更贴近现实,会话层和表示层基本并入应用层。

TCP 三次握手必须记牢:第一次 SYN 客户端 seq=x,第二次 SYN+ACK 服务器 seq=y ack=x+1,第三次 ACK 客户端 seq=x+1 ack=y+1。三次不是两次是为了双向确认能力和防止旧连接请求。四次挥手要记住 TIME_WAIT 在主动关闭方那一边、等 2 个 MSL,作用是确保最后一个 ACK 到达对方、让旧报文消亡。看到”TIME_WAIT 出现在被动关闭方”是错的,被动关闭方是 CLOSE_WAIT。

TCP 可靠性机制四件套:序号确认、重传、流量控制(滑动窗口)、拥塞控制(慢启动、拥塞避免、快重传、快恢复)。滑动窗口管接收方扛不扛得住、由 rwnd 控制;拥塞控制管网络扛不扛得住、由 cwnd 控制,实际发送窗口 = min(rwnd, cwnd)。慢启动指数增长、拥塞避免线性增长,3 个重复 ACK 触发快重传只回到 ssthresh 一半、超时则 cwnd 回到 1——两种拥塞信号恢复策略不同,这个对比要分清。

HTTP 报文分四部分:请求行或状态行、头部、空行、主体。HTTP 方法幂等性:GET、PUT、DELETE 幂等,POST 不幂等。状态码 401 是未认证(没登录或登录失效)、403 是已认证但无权限(登录了但没权限)、404 是资源不存在——三个码最容易混,一定要分清。301 永久重定向、302 临时重定向、304 缓存未变。5xx 里 500 内部错误、502 网关错误、503 服务不可用、504 网关超时。HTTP 缓存分强缓存(Expires、Cache-Control,不问服务器直接用本地)和协商缓存(Last-Modified/If-Modified-Since、ETag/If-None-Match,过期后问服务器有没有变,没变回 304)。

HTTPS = HTTP + SSL/TLS,默认端口 443。握手核心是”非对称加密交换对称密钥,对称加密传数据”——非对称加密慢但安全、对称加密快但密钥分发难,混着用各取所长。客户端发 client_random、服务器发 server_random 和证书、客户端验证证书后用服务器公钥加密 pre_master_secret 发过去、双方用三个随机数算出对称会话密钥。SSL 2.0/3.0 已废弃,主流是 TLS 1.2 和 TLS 1.3。HTTP 协议演进:HTTP/1.1 有持久连接和管道化但有队头阻塞,HTTP/2 用多路复用、头部压缩、服务器推送解决,HTTP/3 改用基于 UDP 的 QUIC 进一步减少握手延迟。

DNS 解析层层递进:浏览器缓存→操作系统缓存和 hosts 文件→本地 DNS 服务器→根 DNS→顶级域 DNS→权威 DNS。客户端到本地 DNS 是递归查询(你替我问到底),本地 DNS 到外面是迭代查询(告诉我下一步问谁)。DNS 还能做负载均衡,把同一域名对应多个 IP 实现流量分发。

同源策略要求协议、域名、端口三者相同,浏览器才允许跨页面访问 Cookie 和 DOM。跨域用 CORS,简单请求直接发并检查响应头,预检请求先发 OPTIONS 问服务器允不允许。Cookie 存客户端、Session 存服务器端,Session 靠 Cookie 里的 Session ID 关联。分布式 Session 三种方案:Session 复制(同步开销大)、集中式存储(Redis 最常用)、Token/JWT(无状态,天然支持分布式)。

IP 分类看第一段数字:1-126 是 A 类、127 环回、128-191 是 B 类、192-223 是 C 类、224-239 是 D 类组播、240-255 是 E 类保留。私有地址三段必须背:10.0.0.0/8、172.16.0.0/12、192.168.0.0/16。特殊地址:127.0.0.0/8 环回、0.0.0.0 本机所有地址、255.255.255.255 广播、169.254.0.0/16 自动私有(DHCP 失败时分配)。

子网划分五步走:算掩码→IP 和掩码按位与得网络地址→网络地址主机位置 1 得广播地址→网络地址+1 到广播地址-1 是可用主机范围→2^(32-n)-2 是可用主机数,减的 2 是网络号和广播。CIDR 用 /n 表示掩码位数不绑定 A/B/C 分类,NAT 让内网共用一个公网 IP 出网、靠端口号区分内部机器。

TCP vs UDP 应用场景:HTTP/HTTPS、FTP、SMTP、SSH 用 TCP 因为要可靠;DNS 查询、视频直播、语音通话、游戏、DHCP 用 UDP 因为要快能容忍丢包。看到”DNS 一定用 UDP”是错的,区域传送用 TCP;”HTTP 一定用 TCP”在 HTTP/3 之前成立,HTTP/3 改用基于 UDP 的 QUIC。

其他重要概念:WebSocket 借 HTTP 握手后切到全双工协议,适合实时通信;CDN 把静态资源缓存到全球节点让用户就近取,降低延迟、减轻源站压力、抗 DDoS;负载均衡分四层(看 IP 端口)和七层(看应用层内容),常见算法有轮询、最少连接、IP 哈希;RESTful API 三原则是 URL 表示资源、HTTP 方法表示操作、无状态。


面试题与实战导向复盘

学习网络时需要多做面试题,单纯考概念很少,更多是结合实际场景问问题。下面从面试考察角度做一次复盘,帮你巩固重点。

高频面试题精讲

1. 为什么 TCP 需要三次握手?两次不行吗?

这是最经典的面试题。核心要点:三次握手是为了双向确认通信能力和防止旧连接请求。第一次握手确认客户端能发,第二次确认服务器能收也能发,第三次确认客户端能收。两次握手只能让客户端确认服务器,但服务器没法确认客户端,万一遇到网络里滞留的旧 SYN,服务器会白建连接。回答时一定要说清楚”双向确认”和”防止旧连接”这两个点。

2. TIME_WAIT 为什么要等 2 个 MSL?出现在哪一方?

TIME_WAIT 出现在主动关闭方,等 2 个 MSL 有两个原因:一是最后一个 ACK 可能丢了,服务器会重传 FIN,客户端得留着状态准备重传;二是让旧报文在网络里自然死亡,防止污染下一次连接。记住一句话:TIME_WAIT 在主动关闭方,等 2MSL 是为了可靠和清理旧包。

3. 滑动窗口和拥塞窗口的区别是什么?

滑动窗口管的是接收方能不能扛得住,由 rwnd 控制,做的是流量控制;拥塞窗口管的是网络能不能扛得住,由 cwnd 控制,做的是拥塞控制。实际发送窗口 = min(rwnd, cwnd)。这个对比一定要分清,面试常考。

4. 401 和 403 的区别是什么?

401 是未认证——“我还不知道你是谁”,需要登录;403 是已认证但无权限——“我知道你是谁,但你没资格”。一句话记住:401 是没登录,403 是登录了但权限不够。

5. HTTP 和 HTTPS 的区别是什么?HTTPS 握手过程是怎样的?

HTTP 明文传输,端口 80;HTTPS 加密传输,端口 443。HTTPS = HTTP + SSL/TLS。握手过程:客户端发 ClientHello(版本、加密套件、client_random)→ 服务器发 ServerHello(选定版本和套件、server_random、证书)→ 客户端验证证书→ 客户端用服务器公钥加密 pre_master_secret 发过去→ 双方用三个随机数算出对称密钥→ 双方发 Change Cipher Spec 和 Finished。核心是”非对称加密交换对称密钥,对称加密传数据”。

6. DNS 解析过程是怎样的?递归查询和迭代查询的区别?

DNS 解析顺序:浏览器缓存→操作系统缓存和 hosts→本地 DNS→根 DNS→顶级域 DNS→权威 DNS。递归查询是”你替我问到底”,迭代查询是”告诉我下一步问谁”。客户端到本地 DNS 是递归,本地 DNS 到外面是迭代。

7. TCP 和 UDP 的应用场景有哪些?为什么?

TCP 适合需要可靠的场景:HTTP/HTTPS、FTP、SMTP、SSH。UDP 适合需要快、能容忍丢包的场景:DNS 查询、视频直播、游戏、DHCP。回答时要结合具体例子说清楚”为什么这个场景选这个协议”,比如 DNS 用 UDP 是因为数据小、要快,建 TCP 太奢侈。

8. 为什么服务器高并发时会有大量 TIME_WAIT?怎么优化?

TIME_WAIT 出现在主动关闭方。如果服务器总是主动断开连接(比如 HTTP 短连接),就会积累大量 TIME_WAIT。优化方法:开启 TCP_TIMEWAIT_REUSE(复用 TIME_WAIT 连接)、调小 tcp_fin_timeout(缩短 TIME_WAIT 时间)、使用长连接减少连接建立和断开次数。

9. 子网划分怎么算?给个例子。

五步走:算掩码→IP 和掩码按位与得网络地址→网络地址主机位置 1 得广播地址→网络地址+1 到广播地址-1 是可用主机范围→2^(32-n)-2 是可用主机数。例子:192.168.1.100/26,网络地址 192.168.1.64,广播地址 192.168.1.127,可用主机范围 65~126,可用主机数 62。

10. HTTP 缓存机制是怎样的?强缓存和协商缓存的区别?

强缓存:浏览器不发请求,直接用本地缓存,靠 Expires 或 Cache-Control: max-age 控制,命中返回 200 from cache。协商缓存:强缓存过期后,浏览器带 If-Modified-Since 或 If-None-Match 问服务器,没变返回 304,变了返回 200 加新资源。区别:强缓存更快(不问服务器),协商缓存更精准(每次确认)。

实战场景分析

场景一:用户输入网址到页面加载,整个过程发生了什么?

这个问题能考察你对整个网络栈的理解。完整流程:DNS 解析(域名→IP)→ 建立 TCP 连接(三次握手)→ 发送 HTTP 请求→ 服务器处理请求→ 返回 HTTP 响应→ 浏览器渲染页面→ TCP 断开连接(四次挥手)。中间每个环节都可能有细节,比如 DNS 解析的层级、TCP 握手的状态变化、HTTP 请求的报文结构等。

场景二:为什么有时候网页打开很慢?可能的原因有哪些?

从网络角度分析:DNS 解析慢(本地 DNS 服务器慢或网络不通)、TCP 握手慢(网络延迟高)、HTTP 请求慢(服务器处理慢或网络拥塞)、传输慢(带宽不够或 CDN 没生效)、渲染慢(资源太大或脚本阻塞)。回答时要分层次说,从底层到上层逐一分析。

场景三:如何优化网站的加载速度?

网络层面:用 CDN 加速静态资源、开启 HTTP 缓存、压缩资源(gzip/brotli)、使用 HTTP/2 多路复用、减少 HTTP 请求数(合并 CSS/JS)、使用长连接减少握手开销。服务器层面:优化代码逻辑、使用缓存(Redis/Memcached)、数据库优化(索引、查询优化)、负载均衡分流。前端层面:懒加载图片、使用合适的图片格式(WebP/AVIF)、减少首屏资源、使用 SSR/SSG。

场景四:HTTPS 如何防止中间人攻击?

核心是 CA 证书机制。服务器向 CA 申请证书,CA 用自己的私钥给服务器的公钥签名。客户端收到证书后,用 CA 的公钥(系统内置)验证签名,确认公钥确实是服务器的。中间人就算截获通信,也伪造不出 CA 的签名,所以没法冒充服务器。

场景五:分布式系统中 Session 怎么共享?

三种方案:Session 复制(服务器之间同步,简单但开销大)、集中式存储(Redis,最常用)、Token/JWT(无状态,天然支持分布式)。每种方案的优缺点要清楚,比如 Redis 方案的优点是性能高、支持过期,缺点是多了一个依赖;JWT 的优点是无状态,缺点是无法主动失效。

复习建议

  1. 抓大放小:重点掌握 TCP 三次握手四次挥手、HTTP/HTTPS、DNS、IP 子网划分这几块,面试考得最多。
  2. 结合场景理解:不要死记概念,要理解每个概念在实际场景中是怎么用的。比如 TIME_WAIT 不是抽象的状态,而是解决”最后一个 ACK 丢了怎么办”的实际问题。
  3. 多画图:三次握手、四次挥手、DNS 解析过程,画图能帮你记住流程。
  4. 做真题:找一些大厂的网络面试题来练,重点看他们怎么考,考哪些知识点。
  5. 动手实践:用 Wireshark 抓包看看 HTTP 请求长什么样,用 ping/tracert 看看网络通不通,用 ipconfig/ifconfig 看看自己的网络配置,实践能加深理解。

计算机网络是入门容易精通难的科目,面试时考的往往不是你记了多少概念,而是你能不能用这些概念分析实际问题。希望这篇博客能帮你打好基础,面试时从容应对。