面试前快速复习版。每节按“问题 → 标准回答 → 讲解 → 追问”展开。


1|问题:OSI 七层和 TCP/IP 四层怎么对应?

面试标准回答

OSI 从上到下是应用、表示、会话、传输、网络、数据链路和物理层。TCP/IP 把 OSI 上三层合为应用层,传输层和网络层分别对应,下面两层合为网络接口层。OSI 适合梳理职责,TCP/IP 更接近实际协议栈。

讲解

OSI主要职责TCP/IP代表协议或数据
应用、表示、会话应用服务、编码、会话应用层HTTP、DNS
传输进程通信、可靠性传输层TCP、UDP
网络寻址、跨网段路由网际层IP
数据链路、物理本地链路交付、信号传输网络接口层以太网、Wi-Fi
HTTP 消息 → TCP 段 → IP 包 → 以太网帧 → 比特流
加端口 加 IP 加 MAC

发送端逐层加头,接收端逐层拆头。每层只解决一类问题:HTTP 表达业务,TCP 找进程并保证传输,IP 负责跨网络寻址,以太网把数据交给本地下一跳。

追问

  • **四层和七层负载均衡?**四层主要看 IP、端口;七层还能看 HTTP 域名、路径和 Header。
  • **交换机和路由器在哪层?**传统交换机工作在数据链路层,路由器工作在网络层。

2|问题:输入域名后,数据怎么找到目标主机?

面试标准回答

DNS 先把域名解析为 IP。主机再用目标 IP 和子网掩码判断是否同网段,并按最长前缀匹配查路由表。同网段时 ARP 查询目标 MAC;跨网段时查询网关 MAC,把 IP 包装进发往下一跳的帧,路由器再逐跳转发。

讲解

域名 ──DNS──> 目标 IP
↓ 查路由表
同网段 ──ARP 查目标 MAC──> 目标主机
跨网段 ──ARP 查网关 MAC──> 网关 ──逐跳路由──> 目标主机

DNS 缓存未命中时,递归解析器通常依次询问根、顶级域和权威 DNS。转发过程中,链路层的源、目标 MAC 每一跳都会变化;端到端 IP 通常不变,但 TTL 会递减,经过 NAT 时 IP 和端口还可能被改写。

追问

  • **为什么不查远端服务器的 MAC?**ARP 广播不跨路由器,只能找到本地链路上的下一跳。
  • **多条路由都匹配怎么办?**选择前缀最长、范围最具体的一条。

3|问题:TCP 和 UDP 应该怎么选?

面试标准回答

文件、交易等不能缺字节的场景通常用 TCP,因为它提供有序、可靠的字节流;实时音视频更怕数据迟到,可以用 UDP,让应用决定哪些包要重传、哪些过期就丢。UDP 无连接、首部小,但不等于任何场景都更快。

讲解

维度TCPUDP
通信方式有连接的字节流无连接的数据报
消息边界不保留保留
可靠性排序、确认、重传、去重不保证送达和顺序
控制机制流量控制、拥塞控制由应用按需实现
首部最小 20 字节固定 8 字节

TCP 连接通常由源 IP、源端口、目标 IP、目标端口四元组标识。QUIC 虽然承载在 UDP 上,却自行实现了可靠传输和拥塞控制,所以“基于 UDP”和“不可靠”不能画等号。

追问

  • **TCP 和 UDP 能用同一端口吗?**可以,内核会先按传输层协议分流。
  • **服务端一个端口为何能接很多连接?**客户端 IP 或临时端口不同,连接四元组就不同。

4|问题:TCP 为什么要三次握手?

面试标准回答

三次握手用来可靠同步双方的初始序列号,并避免历史连接请求造成混淆。客户端先发 SYN 和序列号,服务端用 SYN+ACK 确认并给出自己的序列号,客户端最后回 ACK。两次握手少了对服务端序列号的确认,四次则可以把中间的 SYN 和 ACK 合并。

讲解

客户端 服务端
CLOSED LISTEN
│ SYN, seq=x ─────────────────────────> │ SYN-RECEIVED
│ <────────── SYN+ACK, seq=y, ack=x+1 │
│ ACK, ack=y+1 ───────────────────────> │
ESTABLISHED ESTABLISHED

三次完成后,双方都确认了对方的初始序列号。报文丢失不会改流程:SYN 丢了由客户端重传,SYN+ACK 丢了由服务端重传,最后 ACK 丢了,服务端仍会重传 SYN+ACK。大量只发 SYN 的请求会占用半连接资源,可通过限速、清洗和 SYN cookies 缓解。

追问

  • **第三次握手能带数据吗?**可以,此时客户端已确认服务端的序列号。
  • **没调用 accept() 能握手成功吗?**能,内核先完成握手,连接在 accept 队列等待应用取走。

5|问题:为什么通常是四次挥手?

面试标准回答

TCP 是全双工连接。收到 FIN 只表示对方不再发送,自己可能还有数据,因此两个方向要分别关闭,通常需要四个报文。主动关闭方进入 TIME_WAIT 等待 2MSL;CLOSE_WAIT 表示本地已收到 FIN,但应用还没有关闭套接字。

讲解

主动关闭方 被动关闭方
FIN-WAIT-1 ── FIN ────────────────────> CLOSE-WAIT
FIN-WAIT-2 <─ ACK ─────────────────────
<─ FIN ───────────────────── LAST-ACK
TIME-WAIT ── ACK ─────────────────────> CLOSED

TIME_WAIT 能在最后 ACK 丢失时继续响应重传的 FIN,也给旧报文足够时间从网络中消失。CLOSE_WAIT 没有定时器替应用收尾,持续堆积通常说明代码漏了 close(),或关闭流程被阻塞。被动方没有剩余数据时,ACK 和 FIN 可以合并。

追问

  • **TIME_WAIT 一定在客户端吗?**不一定,谁主动关闭,谁通常进入 TIME_WAIT。
  • **CLOSE_WAIT 多怎么查?**定位进程和线程栈,检查异常分支、阻塞调用及连接是否及时关闭。

6|问题:TCP 如何保证可靠传输?

面试标准回答

TCP 用校验和发现损坏,用序列号排序去重,用累计 ACK 确认连续收到的位置,并通过超时或 3 个重复 ACK 触发重传。滑动窗口允许连续发送多段数据,SACK 还能告知已收到的字节区间,减少重复传输。

讲解

Seq=101 丢失
Seq=201 ──> ACK=101 ①
Seq=301 ──> ACK=101 ②
Seq=401 ──> ACK=101 ③ ──> 快速重传 Seq=101
发送窗口:| 已确认 | 已发送未确认 | 可以发送 | 暂不可发送 |

后续报文让接收方重复确认缺口,发送方收到 3 个重复 ACK 后不必等待超时。没有足够后续数据时,RTO 超时仍负责兜底,并会随连续超时退避。ACK 推进后,发送窗口才向右移动;SACK 只补充已收到的区间,不取代累计 ACK。

追问

  • **一个 ACK 丢了就会重传吗?**不一定,后续更大的累计 ACK 可以一起确认前面的数据。
  • **TCP 能保证业务数据不丢吗?**不能,进程崩溃、落库失败和业务确认要由应用处理。

7|问题:流量控制和拥塞控制有什么区别?

面试标准回答

流量控制保护接收端,由接收方用 rwnd 通告剩余缓冲区;拥塞控制保护中间网络,由发送方根据网络反馈维护 cwnd。实际可发送的在途数据受两者较小值限制。经典拥塞控制包括慢启动、拥塞避免、快速重传和快速恢复。

讲解

实际发送上限 = min(rwnd, cwnd)
接收端来不及处理 ──> rwnd 变小
网络出现拥塞信号 ──> cwnd 变小

接收方慢但网络空闲,应缩小 rwnd;接收方有空间但中间路由器丢包,应缩小 cwnd。经典慢启动阶段窗口按 RTT 快速增长,达到门限后转为较缓慢的拥塞避免。现代系统还可能采用 CUBIC、BBR,不能把所有实现都按 Reno 描述。

追问

  • **接收窗口为零怎么办?**发送方暂停常规发送,并用窗口探测等待接收方恢复。
  • **窗口越大越好吗?**不一定,还受内存和带宽时延积影响,过度排队会增加延迟。

8|问题:TCP 为什么会粘包,怎么拆包?

面试标准回答

TCP 是连续字节流,不保留应用消息边界。两次 send() 可能被一次 recv() 读到,一次发送也可能分多次读取。应用协议必须自己定界,常见方案是固定长度、分隔符,或“长度字段 + 消息体”。

讲解

发送:[长度=5][hello][长度=3][bye]
接收:[长度=5][he] [llo][长度=3][bye]
解析:先读长度 → 累积足够字节 → 交付一条完整消息

send() 只是把字节交给内核缓冲区,recv() 返回当时可读的部分,两者没有一一对应关系。所谓粘包是应用把读取次数误当成消息边界,不是 TCP 出错。UDP 保留数据报边界,但数据报过大仍可能触发 IP 分片。

追问

  • **HTTP 如何定界?**HTTP/1.1 用 Content-Length、分块编码等规则;HTTP/2 和 HTTP/3 用带长度的帧。
  • **读到半包怎么办?**先把数据留在缓冲区,等后续字节到齐再解析。