计算机基础面试重点知识

计算机网络

网络体系结构之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 /displaydns 或 systemd-resolve --statistics 查看)。

  • 如果命中,返回 IP。

  1. hosts 文件
  • 若操作系统缓存未命中,则查找本地的 hosts 文件 (/etc/hosts 或 C:\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。

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

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

对比:建立连接时,服务器可以将 SYN 和 ACK 合并为 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 除了超时重传和快速重传,还有哪些重传优化?
答 :还有 SACK 和 DSACK。

  • 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 小时前
当大模型遇见线束制造:不是通用AI,而是行业AI
大数据·网络·人工智能·安全·制造
91刘仁德3 小时前
IP协议详解:从IP协议头到网段划分、路由与NAT
linux·服务器·网络·网络协议·tcp/ip
可乐鸡翅yeah_4 小时前
业务中 M3U8 水印相关坑,硬水印和动态水印区别
前端·网络·数据库·ffmpeg·m3u8在线
酣大智6 小时前
H3C MSR3600 交换机配置 SSH
网络·ssh·智能路由器
Interview Aid1127 小时前
OpenAI SWE 面试流程
面试·职场和发展
沐浴露z7 小时前
Agent 响应延迟过高?从工具治理角度提供两条思路
前端·网络
我命由我123457 小时前
Photoshop - Photoshop 使用对齐功能定位元素
学习·职场和发展·产品运营·求职招聘·职场发展·产品经理·学习方法
飘尘8 小时前
SVG和Canvas,前端里的两支“画笔”,用的时候怎么选择?
前端·javascript·面试
马六六i8 小时前
市面上正规的IP驱动产业新场景新工具有哪些
大数据·网络·python·tcp/ip
飘尘8 小时前
从"算子"到"AI Infra":大模型背后看不见的那群人在忙什么
人工智能·算法·面试