计算机基础面试重点知识

计算机网络

网络体系结构之TCP/IP的四层结构

1. 应用层

为应用程序提供网络服务,常见协议:

  • HTTP/HTTPS:网页访问

  • FTP:文件传输

  • SMTP/POP3/IMAP:电子邮件收发

  • DNS:域名解析

  • SSH:安全远程登录

  • Telnet:远程终端(不加密)

  • DHCP:动态主机配置(自动分配IP)

2. 传输层

提供端到端的数据传输控制:

  • TCP:面向连接、可靠、字节流(如网页、邮件)

  • UDP:无连接、不可靠但低延迟(如视频、DNS查询)

  • SCTP:流控制传输协议(用于信令)

3. 网络层

负责路由和地址解析:

  • IP(IPv4 / IPv6):核心协议,提供逻辑寻址

  • ICMP:网络控制报文协议(如ping、traceroute)

  • IGMP:互联网组管理协议(组播管理)

  • ARP:地址解析协议(IP→MAC,有时归为链路层)

  • RARP:逆地址解析协议(已淘汰)

4. 网络接口层

处理物理介质上的数据帧传输:

  • 以太网(Ethernet)

  • WiFi(802.11)

  • PPP(点对点协议)

  • 帧中继、ATM

注:ARP和RARP的位置有时有争议,但理解其功能即可。

面试中重点记住 TCP、UDP、IP、ARP、HTTP、DNS 就足够应对多数问题了。

IP协议

1. 寻址

  • 为每一台连接到互联网的设备分配一个唯一的逻辑地址------IP地址 (如 IPv4 的 192.168.1.1 或 IPv6 的 2001:db8::1)。

  • 这个地址用于标识数据包的目标,就像快递单上的发件地址和收件地址。

2. 路由

  • 决定数据包从源主机到目标主机所经过的路径。

  • IP协议根据路由表,将数据包从一个网络设备(路由器)转发到下一个,逐跳传递,最终到达目标网络。

3. 分片与重组

  • 当数据包过大,超过下一跳网络链路能承载的最大传输单元时,IP协议会将数据包拆分成多个较小的分片

  • 到达目标主机后,再由IP层将这些分片重新组装成完整的数据包,交给上层协议(如TCP/UDP)处理。

补充说明

  • 无连接:IP协议在发送数据前不需要建立连接,每个数据包独立处理。

  • 不可靠 :IP不保证数据包一定到达,也不保证顺序正确或没有重复------这些可靠性通常由上层协议 TCP 来保证。

一句话总结:IP协议负责将数据包从源主机"导航"到目标主机,提供寻址和路由能力,并适配不同网络的传输限制。

ARP协议

ARP(Address Resolution Protocol,地址解析协议) 的作用是:在同一个局域网内,根据已知的 IP 地址,解析出对应的 MAC 地址(物理地址)。

为什么需要 ARP?

  • 网络层使用 IP 地址 进行逻辑寻址(跨网络通信)。

  • 链路层(以太网等)使用 MAC 地址 进行物理寻址(同一网络内的设备间通信)。

  • 当一台主机要往同一网段的另一台主机发送数据时,它必须知道目标的 MAC 地址才能封装成数据帧。ARP 就是用来完成这个"IP → MAC"的映射。

工作流程(简化版):

  1. 检查缓存:主机先查看本地的 ARP 缓存表,如果有目标 IP 对应的 MAC 地址,直接使用。

  2. 广播请求 :如果没有,主机发送一个 ARP 广播请求(目标 MAC 为 FF:FF:FF:FF:FF:FF),内容为:"谁拥有 IP 192.168.1.5?请告诉我的 MAC 地址。"

  3. 单播响应 :目标主机收到广播后,发现是自己的 IP,就单播回复一个 ARP 响应,告诉请求者自己的 MAC 地址。

  4. 更新缓存:请求者收到响应后,将 IP-MAC 映射存入缓存,并发送数据。

常见相关知识点):

  • ARP 缓存 :存储最近解析过的 IP-MAC 映射,避免重复广播。可通过 arp -a 查看。

  • ARP 欺骗/攻击:攻击者伪造 ARP 响应,使通信数据被重定向到攻击者机器,属于中间人攻击。

  • 免费 ARP(Gratuitous ARP):主机主动广播自己的 IP-MAC 映射,用于通告地址变更或检测 IP 冲突。

一句话总结:

ARP 是局域网中"IP 地址翻译成 MAC 地址"的翻译官,没有它,同一网段的设备就无法直接通信。

关于HTTP

1. GET 和 POST 的区别

对比项 GET POST
语义 从服务器获取资源 向服务器提交数据,处理请求(如创建/修改资源)
参数位置 参数放在 URL 的查询字符串中(?key=value 参数放在请求体(body)中
长度限制 URL 长度有限制(浏览器/服务器限制,通常 ≤ 2048 字符) 理论上无限制(受服务器配置影响)
安全性 参数暴露在 URL 中,易被浏览器历史、日志记录,不安全 参数在 body 中,相对更安全(但仍需 HTTPS 加密)
幂等性 是(多次相同请求结果相同,不改变服务器状态) 否(多次提交可能创建多个资源)
缓存 可以被浏览器缓存、收藏为书签 默认不被缓存,不可书签
数据类型 只支持 ASCII 字符 支持任意类型(文件、二进制等)

注意:GET 也可以带 body,但规范不推荐,实际使用很少。


2. HTTP 报文结构

请求报文
复制代码
<方法> <请求URL> <版本>
<头部字段>: <值>
...
空行
<请求体>

示例:

复制代码
GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html
响应报文
复制代码
<版本> <状态码> <状态描述>
<头部字段>: <值>
...
空行
<响应体>

示例:

复制代码
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024

<html>...
各部分说明
  • 起始行:方法/URL/版本 或 版本/状态码/短语

  • 头部(Header):键值对,描述元信息(如 Host、Content-Type)

  • 空行:分隔头部和正文

  • 正文(Body):可选,GET 通常无,POST/PUT 携带数据


3. HTTPS 工作流程

HTTPS = HTTP + TLS/SSL(加密层)。核心流程如下:

  1. 客户端发起 HTTPS 请求 (如访问 https://example.com

  2. 服务器返回数字证书:证书包含公钥、域名、颁发机构、有效期等

  3. 客户端验证证书:检查是否受信任、是否过期、域名是否匹配

  4. 客户端生成随机密钥(Premaster Secret),用服务器的公钥加密后发送

  5. 服务器用私钥解密,得到随机密钥

  6. 双方使用相同的随机密钥生成会话密钥(对称加密密钥)

  7. 后续通信使用对称加密(如 AES)进行加密传输,保证机密性和完整性

简单记忆:非对称加密传输对称密钥,对称加密传输数据


对比项 Cookie Session
存储位置 客户端(浏览器) 服务器端(内存/数据库/文件)
大小限制 通常 ≤ 4KB 无大小限制(受服务器资源影响)
安全性 较低,可被用户查看和篡改 较高,存储在服务器
生命周期 可设置过期时间(持久或会话级) 通常由服务器设定超时时间
工作原理 服务器通过 Set-Cookie 响应头写入,后续请求自动携带 服务器生成唯一 Session ID,通常通过 Cookie 传递 Session ID
典型用途 记住用户偏好、跟踪行为 保存用户登录状态、购物车等敏感信息

协作关系

  • 服务器创建 Session 后,将 Session ID 存入 Cookie 返回客户端。

  • 客户端后续请求携带该 Cookie,服务器根据 Session ID 找到对应的 Session 数据。


5. HTTP 状态码(常见分类)

分类 范围 含义 示例
1xx 100-199 信息响应 100 Continue
2xx 200-299 成功 200 OK, 201 Created, 204 No Content
3xx 300-399 重定向 301 Moved Permanently, 302 Found, 304 Not Modified
4xx 400-499 客户端错误 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found
5xx 500-599 服务器错误 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable

6.一次完整的 HTTP 请求过程

以用户访问 http://www.example.com/index.html 为例,完整过程包括以下步骤:

1. DNS 解析
  • 浏览器检查本地 DNS 缓存,若无则向 DNS 服务器发起查询,将域名 www.example.com 解析成 IP 地址(如 93.184.216.34)。
2. 建立 TCP 连接(三次握手)
  • 客户端与服务器通过三次握手建立 TCP 连接,为 HTTP 数据传输提供可靠的字节流通道。
3. 发送 HTTP 请求
  • 客户端构建 HTTP 请求报文(如 GET /index.html HTTP/1.1),通过 TCP 连接发送给服务器。
4. 服务器处理请求并返回响应
  • 服务器解析请求,定位资源,生成 HTTP 响应报文(如状态码 200、HTML 内容等),通过 TCP 连接返回。
5. 浏览器解析渲染
  • 浏览器接收响应,解析 HTML、CSS、JS,渲染页面。若页面包含其他资源(图片、CSS 等),会重复上述过程(可能复用 TCP 连接,取决于 Connection 头)。
6. 关闭 TCP 连接(四次挥手)
  • 非持久连接下,请求-响应完成后关闭连接。HTTP/1.1 默认持久连接,可复用。

简记:DNS → TCP → 请求 → 响应 → 渲染 → 关闭(可选)

DNS解析过程

1.DNS 解析总体流程

以访问 www.example.com 为例,浏览器需要获得该域名的 IP 地址。完整过程如下:

  1. 检查浏览器 DNS 缓存

  2. 检查操作系统 DNS 缓存

  3. 检查 hosts 文件

  4. 向本地 DNS 服务器发起递归查询

  5. 本地 DNS 服务器进行迭代查询(从根域 → 顶级域 → 权威域)

  6. 返回 IP 地址并缓存


2、详细步骤说明

  1. 浏览器缓存
  • 浏览器会缓存最近访问过的域名解析结果(时间较短,通常几十秒到几分钟)。

  • 如果命中,直接返回 IP,结束。

  1. 操作系统缓存
  • 若浏览器缓存未命中,浏览器调用操作系统(如 Windows、Linux)的 DNS 解析器。

  • 操作系统会检查本机的 DNS 缓存(可通过 ipconfig /displaydnssystemd-resolve --statistics 查看)。

  • 如果命中,返回 IP。

  1. hosts 文件
  • 若操作系统缓存未命中,则查找本地的 hosts 文件/etc/hostsC:\Windows\System32\drivers\etc\hosts)。

  • hosts 文件中的映射优先级最高(可手动配置,常用于开发或屏蔽网站)。

  • 如果找到,返回 IP。

  1. 向本地 DNS 服务器发起请求(递归查询)
  • 若以上都没有命中,操作系统会向 本地 DNS 服务器(也称首选 DNS 服务器,通常由 DHCP 分配,如路由器的 DNS 或 114.114.114.114)发出查询请求。

  • 这个请求是 递归查询:本地 DNS 服务器承诺最终会返回一个结果(要么 IP,要么失败)。

  1. 本地 DNS 服务器进行迭代查询

本地 DNS 服务器如果没有缓存该域名的记录,会从根域名服务器开始,依次向下查询,过程如下(以 www.example.com 为例):

a) 查询根域名服务器

  • 本地 DNS 服务器向 根域名服务器 (全球13组)发送请求,问:"www.example.com 的 IP 是多少?"

  • 根域名服务器不直接返回 IP,而是返回 顶级域(TLD)服务器 的地址,告诉它:你去问 .com 的顶级域名服务器。

b) 查询顶级域名服务器(.com TLD)

  • 本地 DNS 服务器向 .com 顶级域名服务器发送请求,问:"www.example.com 的 IP 是多少?"

  • .com TLD 服务器也不返回 IP,而是返回 权威域名服务器 的地址,告诉它:你去问 example.com 的权威服务器。

c) 查询权威域名服务器

  • 本地 DNS 服务器向 example.com 的权威域名服务器发送请求,问:"www.example.com 的 IP 是多少?"

  • 权威服务器返回该域名的 IP 地址(例如 93.184.216.34)。

注意:实际中经常使用 EDNS(0)DNSSEC 等扩展,但核心逻辑不变。

  1. 返回 IP 并逐级缓存
  • 本地 DNS 服务器获得 IP 后,将其返回给操作系统,同时本地 DNS 服务器会缓存这条记录(根据 TTL)。

  • 操作系统收到 IP 后,也缓存到系统 DNS 缓存中,并返回给浏览器。

  • 浏览器缓存该 IP,用于后续请求

3、图示(文字版)

复制代码
用户浏览器 -> 浏览器缓存 -> 操作系统缓存 -> hosts 文件
                                          ↓(未命中)
                              本地 DNS 服务器(递归查询)
                                          ↓
                             根域名服务器(返回 .com TLD 地址)
                                          ↓
                             .com TLD 服务器(返回 example.com 权威服务器地址)
                                          ↓
                             example.com 权威服务器(返回 www 的 IP)
                                          ↓
                              本地 DNS 服务器缓存并返回 IP
                                          ↓
                              操作系统/浏览器缓存,开始 HTTP 请求

4、常见补充概念

递归查询 vs 迭代查询
  • 递归查询 :客户端要求服务器必须返回最终结果(要么 IP,要么错误)。客户端只发一次请求,剩下的事情由服务器完成。

  • 迭代查询:服务器返回一个"参考答案"(如下一级服务器地址),客户端需要自己去查。本地 DNS 服务器向根/顶级/权威服务器发起的查询就是迭代查询。

DNS 缓存的位置与 TTL
  • TTL(Time To Live):DNS 记录的有效期,由域名的管理者设置。缓存时间结束后,解析器会重新查询。

  • 缓存层级:浏览器、操作系统、本地 DNS 服务器、中间路由器等都可能缓存。

DNS 预解析(dns-prefetch)
  • 浏览器可以在页面中提前解析后续可能会用到的域名,减少用户等待时间。例如 <link rel="dns-prefetch" href="//example.com">

关于TCP

三次握手

1、TCP 三次握手的过程

TCP 是面向连接的可靠传输协议,通信前需要通过"三次握手"建立连接。初始状态:客户端和服务器都处于 CLOSED,服务器主动监听进入 LISTEN 状态。

步骤 方向 报文 含义 状态变化
1 客户端 → 服务器 SYN(seq=x) 客户端请求建立连接,并告知自己的初始序列号 x 客户端 → SYN_SENT
2 服务器 → 客户端 SYN + ACK(seq=y, ack=x+1) 服务器同意连接,告知自己的初始序列号 y,并确认收到客户端的 SYN 服务器 → SYN_RCVD,客户端 → ESTABLISHED
3 客户端 → 服务器 ACK(seq=x+1, ack=y+1) 客户端确认服务器的 SYN 服务器 → ESTABLISHED

完成三次握手后,双方进入 ESTABLISHED 状态,可以开始传输数据。

:seq 是序列号,ack 是确认号,都用于可靠传输和顺序控制。


2、为什么不是两次握手?

假设采用 两次握手 (客户端发 SYN,服务器回 SYN+ACK 后即认为连接建立),会带来一个严重问题:历史连接(旧的重复 SYN)可能导致错误建立连接

场景示例:

  1. 客户端发送一个 SYN(seq=100),由于网络拥塞,该报文滞留。

  2. 客户端超时重传另一个 SYN(seq=200),服务器收到并回复 SYN+ACK,两次握手后连接建立,双方传输数据,然后关闭。

  3. 此时,那个滞留的旧 SYN(seq=100)终于到达服务器。服务器以为客户端想再次建立连接,于是回复 SYN+ACK。

  4. 如果是两次握手,服务器会立即认为连接已建立,等待客户端发送数据。但客户端根本没有发起这个连接,不会发送数据,服务器就会一直浪费资源等待,造成 半开连接 和资源浪费。

为什么三次握手能解决?

  • 第三次握手中的 ACK 由客户端根据当前连接状态发送。如果客户端收到的是对旧 SYN 的响应,它会发现 ack 不正确(因为自己期望的是 seq=200 的确认,而不是 100),于是发送 RST 重置连接,服务器就不会误建立连接。

  • 换句话说,第三次握手让客户端有机会拒绝过期的连接请求,保证了连接的可靠性。


3、为什么不是四次握手?

从功能上讲,三次已经足够:

  • 第一次:客户端表明意愿(SYN)

  • 第二次:服务器同意并表明自己意愿(SYN+ACK)

  • 第三次:客户端确认服务器意愿(ACK)

双方各自都得到了对方的确认,序列号也完成了同步。四次握手并没有带来额外的好处,只会增加一次报文传输,降低效率

实际上,TCP 的断开(四次挥手)之所以需要四次,是因为全双工通信需要双方独立关闭。而建立连接时,服务器可以把自己的 SYN 和对客户端 SYN 的 ACK 合并在同一个报文中(即 SYN+ACK),所以三次就够了。


4、补充:第三次握手可以携带数据吗?

可以。第三次握手中的 ACK 报文可以携带应用数据(从 seq=x+1 开始),这叫做"捎带应答",能提高效率。但前两次握手不能携带数据,因为连接尚未完全建立。


一句话总结:三次握手解决了历史连接重复导致的错误建立问题,且效率最优;两次不安全,四次浪费。

SYN、ACK (标志位)和 seq、ack(序号)的含义及其联系
1、SYN 和 ACK(控制标志位)

TCP 报文头部有多个标志位(每个占1比特),用来表示报文类型。其中:

标志位 名称 作用
SYN Synchronize(同步) 用于建立连接。发送 SYN 表示发起连接请求,并告知自己的初始序列号。
ACK Acknowledgment(确认) 用于确认收到数据。ACK=1 表示确认号(ack)字段有效,否则忽略。

其他标志位:FIN(关闭连接)、RST(重置)、PSH(推送)、URG(紧急)等。


2、seq 和 ack(序号字段)

TCP 是面向字节流的可靠传输,每个字节都有编号。序号字段用来标识数据的位置。

字段 全称 含义
seq Sequence Number(序列号) 本报文段所发送数据的第一个字节的序号
ack Acknowledgment Number(确认号) 期望接收到的下一个字节的序号,同时表示对之前所有数据的确认。

注意:小写 seq / ack 是字段;大写 SYN / ACK 是标志位。


3、三次握手中它们是如何工作的?

以客户端发起连接为例(初始 seq 随机为 x,服务器随机为 y):

步骤 方向 报文内容 含义
1 客户端 → 服务器 SYN=1, seq=x 请求连接,告知自己的初始序号 x
2 服务器 → 客户端 SYN=1, ACK=1, seq=y, ack=x+1 同意连接,告知自己的初始序号 y,并确认已收到客户端的 SYN(期望下一个字节是 x+1)
3 客户端 → 服务器 ACK=1, seq=x+1, ack=y+1 确认收到服务器的 SYN,期望下一个字节是 y+1

关键点

  • 为什么 ack = x+1? 因为客户端发来的 SYN 报文虽然没有数据,但也占一个字节的序号(即该 SYN 自身消耗一个序号)。所以服务器确认时,期望收到的下一个字节序号是 x+1。

  • 同理,服务器的 SYN 也消耗一个序号 y,所以客户端回复 ack = y+1。


4、seq 和 ack 的联系(核心)

确认号 ack 总是等于对方发送的最后一个 seq + 该报文所携带的数据字节数(不含标志位,但 SYN 和 FIN 各占一个序号)。

  • 对于普通数据报文:若对方发来 seq=100, 数据长度=20,则我应回复 ack=120,表示我已收到 100~119,期待 120。

  • 对于 SYN 或 FIN 报文:它们虽然不带数据,但也消耗一个序号,所以确认时 ack = seq + 1。

这种设计使得 TCP 能够:

  • 实现累积确认(一次性确认之前所有数据)

  • 检测丢包并重传

  • 保证有序交付


5、简单记忆
  • SYN = 想要建立连接(握手)

  • ACK = 收到了对方的消息(点头)

  • seq = 我发送的数据编号("这是第 x 号包裹")

  • ack = 我已收到哪些,接下来请从哪个编号发("我已收到 x 号及以前,请发 x+1 号")

联系:SYN 和 ACK 是控制语义,seq/ack 是数据位置。握手时通过 seq 交换初始序号,通过 ack 确认对方序号,从而同步双方的字节流序号。

TCP 四次挥手

1、为什么挥手需要四次?

TCP 是全双工通信,双方可以独立关闭自己的数据传输方向。因此关闭连接时需要双方分别确认关闭。

步骤 方向 报文 含义
1 主动关闭方 → 被动关闭方 FIN 主动方说"我没有数据要发了,想关闭我这一侧的连接"
2 被动关闭方 → 主动关闭方 ACK 被动方确认收到 FIN(但自己可能还有数据要发)
3 被动关闭方 → 主动关闭方 FIN 被动方也发完数据了,说"我也可以关闭了"
4 主动关闭方 → 被动关闭方 ACK 主动方确认被动方的 FIN,双方彻底关闭

为什么不能合并为三次?

  • 第 2 步的 ACK 和第 3 步的 FIN 通常不能合并,因为被动关闭方在收到 FIN 后,可能还有数据要发送,需要时间处理。只有当它所有数据都发完后才能发 FIN。

  • 如果合并,意味着被动方同意立即关闭,但可能数据还没发完,导致数据丢失。

  • 所以一般情况下是四次。但特殊情况下(如同时关闭或半关闭),也可能出现三次,不过标准模型是四次。

对比:建立连接时,服务器可以将 SYNACK 合并为 SYN+ACK,因为那时双方都没有待发送的数据,可以一步完成。


2、为什么需要等待 2MSL 才进入 CLOSED?

MSL(Maximum Segment Lifetime)是报文段在网络中的最大生存时间,通常为 2 分钟(实际实现中常见 30 秒、1 分钟或 2 分钟)。

主动关闭方在发送最后一次 ACK(第 4 步)后,会进入 TIME_WAIT 状态,持续 2MSL 时间,然后才进入 CLOSED

原因有两条:

  1. 确保最后的 ACK 能被对方收到,避免对方超时重发 FIN
  • 如果主动方发送的最后一个 ACK 在网络中丢失,被动方收不到确认,会在超时后重发 FIN

  • 如果主动方立即关闭(进入 CLOSED),就收不到这个重发的 FIN,被动方会一直等待,无法正常关闭。

  • 等待 2MSL 期间,主动方仍能接收并响应重发的 FIN(再发一次 ACK),确保被动方正常关闭。

  1. 让本次连接中所有残留的报文段在网络中消失
  • 2MSL 足够让本连接中所有可能滞留在网络中的报文段(包括重复的、延迟的)全部过期失效。

  • 这样可以防止这些旧报文段被误认为是新连接的报文段,造成数据混乱。

简单记忆:2MSL 保证了最后的 ACK 可靠送达,同时清空了网络中的残留报文。


3、补充说明
  • 谁进入 TIME_WAIT? 主动发起关闭的一方(通常是客户端,但也可以是服务器)。

  • TIME_WAIT 持续多久? 2MSL(例如 Linux 中 MSL 默认 30 秒,TIME_WAIT 就是 60 秒)。

  • 为什么不能缩短? 缩短可能导致上述两个问题,破坏 TCP 的可靠关闭机制。


一句话总结:
四次挥手是因为全双工关闭需要双方独立确认;等待 2MSL 是为了保证最后一个 ACK 能被收到,并让网络中的旧报文自然消亡。

TCP如何保证可靠性

1. 连接管理
  • 内容:建立连接(三次握手)和断开连接(四次挥手)。

  • 作用:保证通信双方在数据传输前达成一致状态,在结束后释放资源。

  • 关键点:序列号同步、状态转换(CLOSED、LISTEN、SYN_SENT、ESTABLISHED、FIN_WAIT、TIME_WAIT 等)。


2. 校验和
  • 内容:TCP 报文头部有一个 16 位的校验和字段,覆盖 TCP 伪头部、TCP 头部和 TCP 数据。

  • 作用:检测数据在传输过程中是否发生比特错误(如翻转、损坏)。

  • 关键点:如果校验和不匹配,接收方直接丢弃该报文,不发送确认,触发发送方超时重传。


3. 序列号 / 确认应答
  • 内容

    • 序列号(seq):本报文段所发送数据的第一个字节的编号。

    • 确认号(ack):期望收到的下一个字节的编号,同时表示对之前所有数据的确认。

  • 作用

    • 保证数据按序到达(接收方可重排乱序数据)。

    • 实现可靠传输(发送方根据 ack 知道哪些数据已被接收)。

    • 用于去重(接收方可丢弃重复的 seq)。


4. 流量控制
  • 内容 :通过 滑动窗口 机制,接收方告知发送方自己的接收窗口大小(rwnd)。

  • 作用:防止发送方发送过快,导致接收方缓冲区溢出而丢包。

  • 关键点

    • 接收方在每次确认报文(ACK)中携带窗口大小。

    • 发送方的未确认数据量不能超过接收窗口。

    • 若窗口为 0,发送方会启动持续计时器,定期探测窗口是否恢复。


5. 最大消息长度(MSS)
  • 内容 :TCP 连接建立时,双方在 SYN 报文中协商的单个报文段能携带的最大数据长度(不含 TCP 头部和 IP 头部)。

  • 作用:避免 IP 层分片,提高传输效率。

  • 关键点

    • MSS 通常 = MTU - 40(IPv4 下 TCP 头部 20 字节 + IP 头部 20 字节)。

    • 以太网 MTU=1500,则 MSS=1460 字节。

    • 如果路径 MTU 更小,可能通过 PMTU 发现机制调整。


6. 超时重传
  • 内容:发送方发出一个报文段后,启动一个重传计时器,若在超时时间内未收到 ACK,则重新发送该报文段。

  • 作用:处理丢包,保证可靠传输。

  • 关键点

    • 超时时间(RTO)基于平滑往返时间(SRTT)动态计算。

    • 每次重传会将 RTO 加倍(指数退避),避免网络拥塞恶化。

    • 超时重传与快速重传(基于重复 ACK)是两种丢包恢复机制。


7. 拥塞控制
  • 内容:发送方根据网络拥塞程度动态调整发送速率,避免网络过载。

  • 四个核心算法

    1. 慢启动(Slow Start):拥塞窗口(cwnd)从 1 个 MSS 开始,每收到一个 ACK 翻倍,直到达到慢启动阈值(ssthresh)。

    2. 拥塞避免(Congestion Avoidance):达到 ssthresh 后,cwnd 线性增加(每 RTT 增加 1 MSS)。

    3. 快速重传(Fast Retransmit):收到 3 个重复 ACK 就立即重传丢失的报文段,不等超时。

    4. 快速恢复(Fast Recovery):快速重传后,将 ssthresh 设为当前 cwnd 的一半,cwnd 设为 ssthresh + 3,然后进入拥塞避免。

  • 作用:在保证可靠性的前提下,最大化网络吞吐量,同时避免拥塞崩溃。


总结(面试时可以这样串联)

TCP 通过 连接管理 建立和释放连接;

校验和 检测数据错误;

序列号/确认应答 实现可靠、有序、去重;

流量控制 避免接收方被淹没;

MSS 协商 避免 IP 分片;

超时重传 处理丢包;

拥塞控制 避免网络过载。

这七个机制共同保证了 TCP 的 可靠、有序、不丢不重、流量适配、网络友好 的特性。

TCP 重传机制

当报文段丢失时,TCP 需要重传。主要有两种:超时重传(RTO)快速重传

1. 超时重传
  • 原理 :发送方发送一个报文段后,启动一个重传计时器(RTO,Retransmission Timeout)。如果在 RTO 内没有收到 ACK,则重传该报文段。

  • RTO 计算 :基于平滑往返时间(SRTT)和偏差动态调整,常见公式:RTO = SRTT + 4×RTT偏差

  • 特点 :RTO 较大时重传慢;RTO 过小时可能误重传。每次重传后 RTO 会加倍(指数退避),避免网络拥塞恶化。

2. 快速重传
  • 触发条件 :发送方连续收到 3 个重复的 ACK(Dup ACK),就认为该报文段丢失,立即重传,不等超时。

  • 原理:接收方收到失序报文时会发送对最后一个有序报文的 ACK(即重复 ACK)。例如,期望 seq=100,却收到 seq=200,则发送 ACK=100。连续收到 3 个这样的 ACK 说明 100 丢失。

  • 优势:比超时重传更快,避免长时间等待。

3.SACK(Selective Acknowledgment,选择性确认)
背景问题

标准 TCP 确认是累积确认(ack = 期望的下一个字节),只能告知"已收到连续的最大序号"。如果中间有多个报文段丢失,发送方只知道最早的丢包,但不知道后面哪些已经到达,往往只能重传从丢包开始的所有数据(可能浪费带宽)。

SACK 的作用
  • 允许接收方在 ACK 中额外告知发送方:已经成功收到的非连续数据块(范围列表)。

  • 发送方知道哪些数据已到达,只重传真正丢失的段,避免重复发送已收到的数据。

工作流程
  1. TCP 连接建立时,双方在 SYN 中协商 SACK 选项(需要双方支持)。

  2. 当接收方收到失序数据时,除了发送标准 ACK(期望序号),还在 TCP 头部选项字段中添加 SACK 块 ,例如:
    SACK: [1000-1499] [2000-2499] 表示已收到这两个范围。

  3. 发送方根据 SACK 信息,精确重传缺失的段(如 1500-1999)。

示例

发送方发了 1~5 号段(每个 500 字节):

  • 收到 1、2、4、5,丢失 3。

  • 标准 ACK 只会告诉发送方 ack=1500(期望第 3 段)。

  • 带 SACK 的 ACK 会额外告知:已收到 2000-2499 和 2500-2999(即 4、5 段)。

  • 发送方只重传 1500-1999(第 3 段),而不是从 1500 开始全部重传。

好处
  • 减少不必要的重传,节省带宽。

  • 提高拥塞控制效率(更准确判断丢包情况)。


4.DSACK(Duplicate SACK,重复选择性确认)
背景问题

发送方有时会因误判而重传已经收到的数据(例如,ACK 丢失导致超时重传,或快速重传时重传了已被确认的段)。标准 SACK 无法告知发送方"这个段我已经收到过了"。

DSACK 的作用
  • 接收方在 SACK 块中报告已经重复收到的数据范围

  • 发送方通过 DSACK 得知自己进行了不必要的重传,从而调整重传策略或拥塞控制参数。

工作流程
  1. 接收方收到一个 序号范围与之前已确认范围重叠 的段。

  2. 除了正常 ACK 外,在 SACK 选项中添加一个 DSACK 块 ,该块描述的是重复接收的范围(通常放在第一个 SACK 块)。

  3. 发送方解析后知道:这个段我之前已经发过且被确认了,不必再重传。

示例
  • 发送方发了段 1(seq=1000-1499),收到 ACK 确认。

  • 由于 ACK 丢失,发送方超时重传同样的段 1。

  • 接收方收到重复段 1,在 ACK 中携带 DSACK:DSACK: [1000-1499]

  • 发送方看到 DSACK,意识到可能是网络延迟或自身 RTO 过小,会调整重传计时器,避免后续无谓重传。

好处
  • 帮助发送方检测不必要的重传,优化 RTO 和拥塞窗口调整。

  • 避免因重传重复数据而浪费带宽。

  • 对拥塞控制算法更友好(例如,不会因误重传而错误判断丢包)。


5.SACK 与 DSACK 对比
特性 SACK DSACK
核心功能 告知已收到的非连续数据块 告知已收到重复数据块
解决的问题 发送方只知道最早的丢包,导致过度重传 发送方误重传已确认数据,浪费带宽并误导拥塞控制
信息内容 已成功接收但不连续的范围 已重复接收的范围
使用场景 多个报文段丢失时 重传了已经确认的报文段时
依赖条件 双方协商 SACK 选项 必须在启用 SACK 的基础上才能使用 DSACK

面试中如何回答

:TCP 除了超时重传和快速重传,还有哪些重传优化?
:还有 SACKDSACK

  • SACK 让接收方告知发送方已收到的非连续数据块,发送方只重传真正丢失的部分,避免重复发送已到达的数据。

  • DSACK 让接收方告知发送方收到了重复数据,发送方可以知道自己的重传是不必要的,从而调整 RTO 或拥塞控制参数。

    两者都需要在连接建立时协商支持。

TCP 流量控制

  • 目的:防止发送方发送过快导致接收方缓冲区溢出。

  • 机制滑动窗口 ,接收方在 ACK 中携带 接收窗口(rwnd),告知发送方还能接收多少字节。

  • 发送方:未确认的数据量不能超过 rwnd。

  • 零窗口 :若 rwnd = 0,发送方停止发送,启动持续计时器,定期发送窗口探测包,询问窗口是否恢复。

  • 与拥塞控制的区别:流量控制是端到端的(接收方能力),拥塞控制是网络层面的(路径拥塞)。


TCP 拥塞控制

  • 目的:避免发送方注入过多数据导致网络拥塞(路由器队列溢出、丢包、延迟增大)。

  • 核心变量拥塞窗口(cwnd) ,发送方能发送的数据量为 min(cwnd, rwnd)

  • 四个算法:慢启动、拥塞避免、拥塞发生、快速恢复。

1. 慢启动
  • 初始:cwnd = 1 MSS(或 2~4 MSS,取决于实现)。

  • 增长方式:每收到一个 ACK,cwnd 翻倍(指数增长)。

  • 结束条件

    • 达到 慢启动阈值(ssthresh),进入拥塞避免。

    • 发生丢包(超时或快速重传)。

2. 拥塞避免
  • 进入条件:cwnd >= ssthresh。

  • 增长方式 :每收到一个 ACK,cwnd 增加 1/cwnd(即每 RTT 增加 1 MSS,线性增长)。

  • 目的:缓慢增加窗口,探测网络容量。

3. 拥塞发生(处理丢包)

根据丢包类型不同,处理方式不同:

a) 超时重传导致的拥塞
  • ssthresh = cwnd / 2(至少 2 MSS)

  • cwnd = 1 MSS(重新慢启动)

  • 这是最严重的拥塞,网络可能完全阻塞。

b) 快速重传(收到3个重复ACK)导致的拥塞
  • 这是轻度拥塞,使用 快速恢复 算法。
4. 快速恢复
  • 步骤(经典 TCP Reno):

    1. ssthresh = cwnd / 2

    2. cwnd = ssthresh + 3(加3是因为已收到3个重复ACK,表示有3个段已经离开网络)

    3. 每收到一个重复 ACK,cwnd += 1

    4. 当收到新的 ACK(确认新数据),cwnd = ssthresh,进入拥塞避免。

  • 目的:避免进入慢启动,快速恢复到拥塞前的窗口大小。

注意:TCP Tahoe 没有快速恢复,遇到重复 ACK 也会将 cwnd 设为 1。


常用算法总结
阶段 算法 窗口变化
连接建立后 慢启动 指数增长至 ssthresh
达到阈值 拥塞避免 线性增长(每RTT +1)
超时 拥塞发生 ssthresh = cwnd/2,cwnd=1,慢启动
快速重传 快速恢复 ssthresh = cwnd/2,cwnd = ssthresh+3,线性增加至新ACK后回到拥塞避免
面试常见追问

Q:为什么需要拥塞控制和流量控制两种机制?

A:流量控制保证接收方不被淹没(端到端);拥塞控制保证网络不被过载(全局)。两者独立但协同。

Q:如何区分丢包是拥塞还是线路错误?

A:TCP 默认认为所有丢包都是拥塞造成的(网络路径可能出错,但设计上按拥塞处理)。在无线网络环境中,这会导致性能下降,于是有了 TCP 的改进版本(如 TCP Westwood)。

Q:快速重传后为什么还要快速恢复?

A:快速重传已经确认网络还有能力传输(因为收到了重复ACK),所以不必像超时那样降为1,只需减半窗口再线性增加,保持较高吞吐量。

TCP 和 UDP 的区别

对比维度 TCP UDP
连接性 面向连接(需三次握手建立连接) 无连接(发送前无需建立连接)
可靠性 可靠传输(确认、重传、校验和) 不可靠(尽最大努力交付,不保证到达)
数据顺序 保证按序到达(通过序列号) 不保证顺序,可能乱序
流量控制 有(滑动窗口)
拥塞控制 有(慢启动、拥塞避免等)
报文边界 字节流,无边界(应用需自行分包) 数据报,保留边界(每个UDP包独立)
开销 头部20字节,开销大 头部8字节,开销小
速度 较慢 较快(适合实时应用)
典型应用 HTTP、FTP、SSH、SMTP DNS、视频直播、VoIP、游戏

一句话总结:TCP 是可靠、有序、有连接的字节流协议;UDP 是不可靠、无序、无连接的数据报协议,但速度快、开销小。


UDP 如何保证消息不丢失?

注意:UDP 协议本身不保证消息不丢失 ,它只提供"尽力而为"的交付。如果要在 UDP 上实现可靠传输,需要在 应用层 增加可靠性机制。

常用的应用层方案包括:

  1. 确认机制(ACK)
  • 接收方收到 UDP 消息后,向发送方回复一个确认消息(ACK)。

  • 发送方若在一定时间内未收到 ACK,则认为消息丢失,进行重传。

  1. 超时重传
  • 发送方为每个 UDP 报文设置一个计时器。

  • 超时未收到 ACK,则重传该报文(可设置重传次数上限)。

  1. 序列号
  • 为每个 UDP 报文添加一个递增的序列号(Seq)。

  • 接收方根据序列号判断是否有报文丢失,并通知发送方重传。

  1. 冗余发送
  • 对关键数据,连续发送多次(如每次发 3 份),接收方只要收到一份即可。但这会占用更多带宽。
  1. 前向纠错(FEC,Forward Error Correction)
  • 发送方发送原始数据的同时,发送一些冗余校验数据。

  • 接收方即使丢了一部分包,也能通过冗余数据恢复原始内容,无需重传。

  1. 流量控制与拥塞控制
  • 应用层可以模拟 TCP 的滑动窗口和拥塞控制,避免发送过快导致丢包。

实际案例:

  • QUIC 协议(基于 UDP)实现了可靠性、有序交付、拥塞控制,可视为"UDP 上的 TCP"。

  • RTP + RTCP(实时传输协议)通过 RTCP 反馈丢包信息,应用层自行重传。

  • 游戏 UDP 中,只有关键状态(如位置、得分)需要 ACK 重传,非关键数据(如动画特效)可以丢失。


一句话总结 :UDP 自身不保证不丢包,但通过应用层添加 ACK、重传、序列号、FEC 等机制,可以做到类似 TCP 的可靠性,代价是增加了实现复杂度。

相关推荐
木斯佳2 小时前
前端八股文面经大全:字节TikTok前端一面(2026-04-17)·面经深度解析
前端·面试·八股·面经
zmj3203242 小时前
TCP/IP协议和以太网关系
网络·网络协议·tcp/ip
hqyjzsb2 小时前
AI培训课程怎么设计才有效?
人工智能·职场和发展·aigc·产品经理·学习方法·业界资讯·设计语言
Wect3 小时前
深度解析浏览器本地存储:原理、方案与实战指南
前端·面试·浏览器
古月方枘Fry3 小时前
三层交换+VRRP实现负载
开发语言·网络·php
Ruihong3 小时前
Vue v-on 在 React 中 VuReact 会如何实现?
vue.js·react.js·面试
byoass3 小时前
企业云盘私有化部署:存储架构设计与安全运维全流程实战
运维·网络·安全·云计算
以神为界3 小时前
数据库入门全指南:从基础概念到实操操作(含SQL+Navicat)
网络·数据库·sql·安全
XGeFei3 小时前
【表单处理】——如何防止CSRF(跨站请求伪造)攻击的?
前端·网络·csrf