Organized 50 interview questions into 12 categories: - 01-分布式系统 (9 files): 分布式事务, 分布式锁, 一致性哈希, CAP理论, etc. - 02-数据库 (2 files): MySQL索引优化, MyBatis核心原理 - 03-缓存 (5 files): Redis数据结构, 缓存问题, LRU算法, etc. - 04-消息队列 (1 file): RocketMQ/Kafka - 05-并发编程 (4 files): 线程池, 设计模式, 限流策略, etc. - 06-JVM (1 file): JVM和垃圾回收 - 07-系统设计 (8 files): 秒杀系统, 短链接, IM, Feed流, etc. - 08-算法与数据结构 (4 files): B+树, 红黑树, 跳表, 时间轮 - 09-网络与安全 (3 files): TCP/IP, 加密安全, 性能优化 - 10-中间件 (4 files): Spring Boot, Nacos, Dubbo, Nginx - 11-运维 (4 files): Kubernetes, CI/CD, Docker, 可观测性 - 12-面试技巧 (1 file): 面试技巧和职业规划 All files renamed to Chinese for better accessibility and organized into categorized folders for easier navigation. Generated with [Claude Code](https://claude.com/claude-code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
578 lines
15 KiB
Markdown
578 lines
15 KiB
Markdown
# TCP/IP 网络协议
|
||
|
||
## 问题
|
||
|
||
1. TCP 和 UDP 的区别是什么?
|
||
2. TCP 三次握手和四次挥手的流程是什么?为什么需要三次握手?
|
||
3. TCP 如何保证可靠传输?
|
||
4. 什么是 SYN 洪水攻击?如何防范?
|
||
5. HTTP 和 HTTPS 的区别是什么?
|
||
6. HTTP 1.1、2.0、3.0 的演进历程和主要特性
|
||
7. 什么是粘包和拆包?如何解决?
|
||
8. 在实际项目中遇到过哪些网络问题?
|
||
|
||
---
|
||
|
||
## 标准答案
|
||
|
||
### 1. TCP vs UDP
|
||
|
||
#### **对比表**
|
||
|
||
| 特性 | TCP | UDP |
|
||
|------|-----|-----|
|
||
| **连接性** | 面向连接 | 无连接 |
|
||
| **可靠性** | 可靠传输 | 不可靠 |
|
||
| **顺序** | 保证顺序 | 不保证顺序 |
|
||
| **速度** | 较慢 | 快 |
|
||
| **流量控制** | 有(滑动窗口) | 无 |
|
||
| **拥塞控制** | 有 | 无 |
|
||
| **首部开销** | 20-60 字节 | 8 字节 |
|
||
| **应用场景** | 文件传输、邮件、HTTP | 视频流、直播、DNS |
|
||
|
||
---
|
||
|
||
#### **TCP 特性**
|
||
|
||
**面向连接**:
|
||
```
|
||
客户端 服务器
|
||
│ │
|
||
│─────── SYN ───────────────→│ 建立连接
|
||
│←────── SYN+ACK ────────────│
|
||
│─────── ACK ───────────────→│
|
||
│ │
|
||
│─────── 数据 ───────────────→│
|
||
│←─────── ACK ───────────────│
|
||
│ │
|
||
│─────── FIN ───────────────→│ 断开连接
|
||
│←─────── ACK ───────────────│
|
||
│←────── FIN ────────────────│
|
||
│─────── ACK ───────────────→│
|
||
```
|
||
|
||
**可靠传输**:
|
||
- 确认应答(ACK)
|
||
- 超时重传
|
||
- 校验和
|
||
- 序列号
|
||
|
||
**流量控制**:
|
||
- 滑动窗口协议
|
||
- 动态调整窗口大小
|
||
|
||
---
|
||
|
||
#### **UDP 特性**
|
||
|
||
**无连接、不可靠**:
|
||
```
|
||
客户端 服务器
|
||
│ │
|
||
│─────── 数据报 ─────────────→│ (可能丢失)
|
||
│─────── 数据报 ─────────────→│ (可能乱序)
|
||
│ │
|
||
│ │
|
||
```
|
||
|
||
**优点**:
|
||
- 速度快(无连接、无确认)
|
||
- 开销小(首部 8 字节)
|
||
- 支持一对一、一对多、多对多
|
||
|
||
**应用场景**:
|
||
- 视频直播(可容忍丢帧)
|
||
- 在线游戏(实时性要求高)
|
||
- DNS 查询(请求响应快)
|
||
- VoIP(语音通话)
|
||
|
||
---
|
||
|
||
### 2. TCP 三次握手和四次挥手
|
||
|
||
#### **三次握手**
|
||
|
||
**流程**:
|
||
```
|
||
客户端 服务器
|
||
│ │
|
||
│─────── SYN=1, seq=x ──────→│ SYN_SENT
|
||
│ │
|
||
│←───── SYN=1, ACK=1, seq=y, ack=x+1 ───│
|
||
│ SYN_RCVD │
|
||
│ │
|
||
│─────── ACK=1, seq=x+1, ack=y+1 ────→│ ESTABLISHED
|
||
│ ESTABLISHED │
|
||
```
|
||
|
||
**状态变化**:
|
||
```
|
||
客户端:CLOSED → SYN_SENT → ESTABLISHED
|
||
服务器:CLOSED → LISTEN → SYN_RCVD → ESTABLISHED
|
||
```
|
||
|
||
---
|
||
|
||
#### **为什么需要三次握手?**
|
||
|
||
**目的**:
|
||
1. **确认双方收发能力**:
|
||
- 第一次握手:服务端确认客户端能发
|
||
- 第二次握手:客户端确认服务端能收能发
|
||
- 第三次握手:服务端确认客户端能收
|
||
|
||
2. **防止已失效的连接请求突然又传送到服务端**:
|
||
```
|
||
场景:客户端发送的第一个连接请求在网络中滞留
|
||
结果:客户端超时重发,建立连接后,滞留的请求到达
|
||
|
||
如果只有两次握手:
|
||
─ 客户端发送 SYN
|
||
─ 服务器收到,建立连接,等待数据
|
||
─ 滞留的 SYN 到达,服务器又建立连接(错误!)
|
||
|
||
三次握手避免:
|
||
─ 服务器收到滞留的 SYN,回复 SYN+ACK
|
||
─ 客户端发现 ack 不对,丢弃(不建立连接)
|
||
```
|
||
|
||
3. **同步初始序列号(ISN)**:
|
||
- 双方协商好初始序列号
|
||
- 保证数据的顺序和去重
|
||
|
||
---
|
||
|
||
#### **四次挥手**
|
||
|
||
**流程**:
|
||
```
|
||
客户端 服务器
|
||
│ │
|
||
│─────── FIN=1, seq=u ──────→│ FIN_WAIT1
|
||
│ │ CLOSE_WAIT
|
||
│←─────── ACK=1, seq=v, ack=u+1 ───│
|
||
│ FIN_WAIT2 │
|
||
│ │
|
||
│←─────── FIN=1, ACK=1, seq=w, ack=u+1 ───│
|
||
│ TIME_WAIT │ LAST_ACK
|
||
│ │
|
||
│─────── ACK=1, seq=u+1, ack=w+1 ────→│ CLOSED
|
||
│ (等待 2MSL) │
|
||
```
|
||
|
||
**状态变化**:
|
||
```
|
||
客户端:ESTABLISHED → FIN_WAIT1 → FIN_WAIT2 → TIME_WAIT → CLOSED
|
||
服务器:ESTABLISHED → CLOSE_WAIT → LAST_ACK → CLOSED
|
||
```
|
||
|
||
---
|
||
|
||
#### **为什么需要四次挥手?**
|
||
|
||
**原因**:
|
||
- TCP 是**全双工**协议(双向传输)
|
||
- 双方都需要关闭发送方向
|
||
|
||
**流程**:
|
||
1. 客户端发送 FIN(关闭客户端→服务器方向)
|
||
2. 服务器确认 ACK(但服务器可能还有数据要发送)
|
||
3. 服务器发送 FIN(关闭服务器→客户端方向)
|
||
4. 客户端确认 ACK
|
||
|
||
---
|
||
|
||
#### **为什么 TIME_WAIT 状态需要等待 2MSL?**
|
||
|
||
**MSL(Maximum Segment Lifetime)**:
|
||
- 报文最大生存时间(通常 30 秒 - 2 分钟)
|
||
- 2MSL = 1 分钟 - 4 分钟
|
||
|
||
**目的**:
|
||
1. **确保最后一个 ACK 能到达**:
|
||
- 如果 ACK 丢失,服务器会重传 FIN
|
||
- 客户端等待 2MSL,可以重传 ACK
|
||
|
||
2. **让旧连接的报文自然消失**:
|
||
- 防止旧连接的报文干扰新连接
|
||
- 确保网络中所有旧报文都已消失
|
||
|
||
**问题**:
|
||
- 大量 TIME_WAIT 会导致端口资源耗尽
|
||
- 解决:调低 `TIME_WAIT` 时间或端口复用
|
||
|
||
```bash
|
||
# Linux 调整
|
||
net.ipv4.tcp_tw_reuse = 1 # 端口复用
|
||
net.ipv4.tcp_tw_recycle = 0 # 关闭快速回收(有坑)
|
||
```
|
||
|
||
---
|
||
|
||
### 3. TCP 可靠传输机制
|
||
|
||
#### **核心机制**
|
||
|
||
1. **序列号(Sequence Number)**:
|
||
- 每个字节都有编号
|
||
- 用于排序和去重
|
||
|
||
2. **确认应答(ACK)**:
|
||
- 接收方确认收到的数据
|
||
- ACK = 下一个期望接收的字节序号
|
||
|
||
```
|
||
发送方:seq=1000, len=100
|
||
接收方:ack=1100(期待下一个字节)
|
||
```
|
||
|
||
3. **超时重传(RTO)**:
|
||
- 发送方启动定时器
|
||
- 超时未收到 ACK,重传数据
|
||
|
||
4. **快速重传**:
|
||
- 收到 3 个重复 ACK,立即重传
|
||
- 无需等待超时
|
||
|
||
```
|
||
发送方:seq=1000, len=100
|
||
接收方:期望 1100,但收到 1200(乱序)
|
||
接收方:连续发送 ack=1100(3 次)
|
||
发送方:收到 3 个重复 ack,快速重传
|
||
```
|
||
|
||
5. **滑动窗口**:
|
||
- 流量控制
|
||
- 动态调整发送速率
|
||
|
||
6. **拥塞控制**:
|
||
- 慢启动、拥塞避免、快重传、快恢复
|
||
|
||
---
|
||
|
||
### 4. SYN 洪水攻击
|
||
|
||
#### **攻击原理**
|
||
|
||
**场景**:攻击者发送大量 SYN 包,但不完成三次握手。
|
||
|
||
```
|
||
攻击者 服务器
|
||
│ │
|
||
├─── SYN ─────────────────────→│ 分配资源
|
||
├─── SYN ─────────────────────→│ 分配资源
|
||
├─── SYN ─────────────────────→│ 分配资源
|
||
├─── SYN ─────────────────────→│ 分配资源
|
||
│ (不回复 ACK) │ 资源耗尽
|
||
│ │ 无法服务正常用户
|
||
```
|
||
|
||
**后果**:
|
||
- 服务器维护大量 `SYN_RCVD` 连接
|
||
- 内存资源耗尽
|
||
- 无法响应正常用户的连接请求
|
||
|
||
---
|
||
|
||
#### **防范措施**
|
||
|
||
**1. SYN Cookies**:
|
||
```bash
|
||
# 开启 SYN Cookies
|
||
net.ipv4.tcp_syncookies = 1
|
||
```
|
||
|
||
**原理**:
|
||
- 不分配资源
|
||
- 计算 Cookie 并编码在 SYN+ACK 的初始序列号中
|
||
- 客户端回复 ACK 时验证 Cookie
|
||
|
||
**2. 增加 SYN 队列**:
|
||
```bash
|
||
net.ipv4.tcp_max_syn_backlog = 8192
|
||
```
|
||
|
||
**3. 缩短超时时间**:
|
||
```bash
|
||
net.ipv4.tcp_synack_retries = 2
|
||
```
|
||
|
||
**4. 防火墙**:
|
||
- 限制单个 IP 的连接数
|
||
- 检测异常流量并拦截
|
||
|
||
---
|
||
|
||
### 5. HTTP vs HTTPS
|
||
|
||
#### **对比**
|
||
|
||
| 特性 | HTTP | HTTPS |
|
||
|------|------|-------|
|
||
| **协议** | 应用层 | 应用层 + 安全层(SSL/TLS) |
|
||
| **端口** | 80 | 443 |
|
||
| **加密** | 明文传输 | 加密传输 |
|
||
| **证书** | 不需要 | 需要 CA 证书 |
|
||
| **性能** | 快 | 较慢(TLS 握手) |
|
||
| **SEO** | 无优惠 | 搜索引擎优先排名 |
|
||
|
||
---
|
||
|
||
#### **HTTPS 工作流程**
|
||
|
||
```
|
||
客户端 服务器
|
||
│ │
|
||
│─────── ClientHello ────────────→│ (支持的加密套件)
|
||
│ │
|
||
│←────── ServerHello ─────────────│ (选择的加密套件 + 证书)
|
||
│←────── Certificate ─────────────│
|
||
│ │
|
||
│─────── ClientKeyExchange ─────→│ (生成随机数)
|
||
│─────── ChangeCipherSpec ───────→│ (之后消息加密)
|
||
│─────── Finished ───────────────→│
|
||
│ │
|
||
│←────── ChangeCipherSpec ────────│
|
||
│←────── Finished ────────────────│
|
||
│ │
|
||
│══════ 加密通信 ══════════════════│
|
||
```
|
||
|
||
---
|
||
|
||
#### **HTTPS 的安全性**
|
||
|
||
1. **数据加密**:防止中间人窃听
|
||
2. **数据完整性**:防止数据被篡改
|
||
3. **身份认证**:防止钓鱼网站
|
||
|
||
---
|
||
|
||
### 6. HTTP 版本演进
|
||
|
||
#### **HTTP/1.0**
|
||
|
||
**特点**:
|
||
- 每个请求都需要新的 TCP 连接
|
||
- 无状态、无连接
|
||
|
||
**问题**:
|
||
- 性能差(频繁建立连接)
|
||
- 队头阻塞
|
||
|
||
---
|
||
|
||
#### **HTTP/1.1**
|
||
|
||
**改进**:
|
||
1. **持久连接**:`Connection: keep-alive`
|
||
2. **管道化(Pipelining)**:可发送多个请求
|
||
3. **分块传输**:`Transfer-Encoding: chunked`
|
||
4. **缓存**:更强的缓存控制
|
||
|
||
**问题**:
|
||
- 队头阻塞仍然存在
|
||
- 请求串行执行
|
||
|
||
---
|
||
|
||
#### **HTTP/2.0**
|
||
|
||
**改进**:
|
||
1. **二进制协议**:不再是纯文本
|
||
2. **多路复用**:一个 TCP 连接并发多个请求
|
||
3. **头部压缩**:HPACK 算法
|
||
4. **服务端推送**:Server Push
|
||
|
||
**多路复用**:
|
||
```
|
||
HTTP/1.1:
|
||
请求1 → ━━━ 连接1 ━━━ → 响应1
|
||
请求2 → ━━━ 连接2 ━━━ → 响应2
|
||
请求3 → ━━━ 连接3 ━━━ → 响应3
|
||
|
||
HTTP/2.0:
|
||
请求1 ┓
|
||
请求2 ┣━━━━ 单连接 ━━━→ ┳ 响应1
|
||
请求3 ┛ ┻ 响应2
|
||
响应3
|
||
```
|
||
|
||
---
|
||
|
||
#### **HTTP/3.0(QUIC)**
|
||
|
||
**改进**:
|
||
1. **基于 UDP**:不再是 TCP
|
||
2. **解决队头阻塞**:流级别隔离
|
||
3. **更快握手**:0-RTT
|
||
4. **连接迁移**:IP 变化不影响连接
|
||
|
||
**架构**:
|
||
```
|
||
HTTP/3.0
|
||
↓
|
||
QUIC(UDP)
|
||
↓
|
||
加密、可靠传输、流控制
|
||
```
|
||
|
||
---
|
||
|
||
### 7. 粘包和拆包
|
||
|
||
#### **问题**
|
||
|
||
**TCP 是字节流协议**,无消息边界:
|
||
|
||
```
|
||
发送方发送两个包:
|
||
┌──────┐ ┌──────┐
|
||
│ 包1 │ │ 包2 │
|
||
└──────┘ └──────┘
|
||
|
||
接收方可能收到:
|
||
1. 正常:┌──────┐┌──────┐
|
||
2. 粘包:┌──────┐┌──────┐(两个包粘在一起)
|
||
3. 拆包:┌────┐ ┌──┐┌──┐┌────┐(包被拆散)
|
||
```
|
||
|
||
---
|
||
|
||
#### **解决方案**
|
||
|
||
**1. 固定长度**:
|
||
```
|
||
每个包固定 100 字节
|
||
|
||
优点:简单
|
||
缺点:浪费空间(短消息)
|
||
```
|
||
|
||
**2. 分隔符**:
|
||
```
|
||
每个包以 \n 结束
|
||
|
||
优点:实现简单
|
||
缺点:内容中不能有分隔符
|
||
```
|
||
|
||
**3. 长度字段(推荐)**:
|
||
```
|
||
┌────┬──────────┐
|
||
│长度│ 数据 │
|
||
└────┴──────────┘
|
||
|
||
实现:Netty 的 LengthFieldBasedFrameDecoder
|
||
```
|
||
|
||
**Netty 示例**:
|
||
```java
|
||
// 服务端
|
||
public class Server {
|
||
public static void main(String[] args) {
|
||
EventLoopGroup bossGroup = new NioEventLoopGroup();
|
||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||
|
||
try {
|
||
ServerBootstrap bootstrap = new ServerBootstrap();
|
||
bootstrap.group(bossGroup, workerGroup)
|
||
.channel(NioServerSocketChannel.class)
|
||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||
@Override
|
||
protected void initChannel(SocketChannel ch) {
|
||
// 解决粘包拆包:长度字段解码器
|
||
ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(
|
||
1024 * 1024, // 最大帧长度
|
||
4, // 长度字段偏移量
|
||
4, // 长度字段长度
|
||
0, // 长度调整值
|
||
4 // 剥离的字节数
|
||
));
|
||
ch.pipeline().addLast(new MessageHandler());
|
||
}
|
||
});
|
||
|
||
bootstrap.bind(8080).sync().channel().closeFuture().sync();
|
||
} finally {
|
||
bossGroup.shutdownGracefully();
|
||
workerGroup.shutdownGracefully();
|
||
}
|
||
}
|
||
}
|
||
|
||
// 消息编解码
|
||
public class MessageEncoder extends MessageToByteEncoder<Message> {
|
||
@Override
|
||
protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) {
|
||
byte[] data = msg.getBody().getBytes();
|
||
out.writeInt(data.length); // 长度字段
|
||
out.writeBytes(data); // 数据字段
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 8. 实际项目经验
|
||
|
||
#### **案例 1:TCP 长连接异常断开**
|
||
|
||
**问题**:
|
||
- 客户端崩溃,服务器未收到 FIN
|
||
- 服务器维护大量死连接
|
||
|
||
**解决**:
|
||
```java
|
||
// 启用 TCP Keep-Alive
|
||
socket.setKeepAlive(true);
|
||
|
||
// 应用层心跳
|
||
@Scheduled(fixedRate = 30000)
|
||
public void sendHeartbeat() {
|
||
channel.writeAndFlush(new HeartbeatMessage());
|
||
}
|
||
|
||
// 超时断开
|
||
ch.pipeline().addLast(new IdleStateHandler(60, 0, 0, TimeUnit.SECONDS));
|
||
ch.pipeline().addLast(new HeartbeatHandler());
|
||
```
|
||
|
||
---
|
||
|
||
#### **案例 2:HTTPS 性能优化**
|
||
|
||
**问题**:
|
||
- HTTPS 握手耗时 200ms+
|
||
- 高并发下性能差
|
||
|
||
**解决**:
|
||
1. **HTTP/2 多路复用**
|
||
2. **TLS False Start**:减少 1 个 RTT
|
||
3. **Session Resumption**:恢复会话
|
||
4. **HSTS**:强制 HTTPS,避免重定向
|
||
|
||
---
|
||
|
||
### 9. 阿里 P7 加分项
|
||
|
||
**深度理解**:
|
||
- 理解 TCP 的拥塞控制算法( Reno、Cubic、BBR)
|
||
- 理解 QUIC 协议的设计原理
|
||
- 理解 TLS 1.3 的改进(0-RTT、加密握手)
|
||
|
||
**实战经验**:
|
||
- 有处理网络抖动导致的连接不稳定问题
|
||
- 有 TCP 参数调优经验
|
||
- 有 HTTPS 性能优化经验
|
||
|
||
**架构能力**:
|
||
- 能设计高性能的网络通信框架
|
||
- 能设计跨地域的网络架构
|
||
- 有网络监控和故障排查经验
|
||
|
||
**技术选型**:
|
||
- 了解 gRPC、Thrift 等 RPC 框架
|
||
- 了解 Netty、Mina 等网络框架
|
||
- 能根据业务特点选择合适的协议
|