🎫 TCP半连接队列和全连接队列:餐厅的"等位区"

36 阅读5分钟

知识点编号:008
难度等级:⭐⭐⭐(必掌握)
面试频率:🔥🔥🔥🔥🔥


🎯 一句话总结

半连接队列是"预约区"(握手中),全连接队列是"等位区"(握手完成)!


🤔 两个队列是什么?

客户端连接服务器的过程:

1️⃣ 客户端发送SYN
   → 进入半连接队列(SYN Queue)
   
2️⃣ 服务器回复SYN+ACK
   
3️⃣ 客户端发送ACK
   → 从半连接队列移到全连接队列(Accept Queue)
   
4️⃣ 应用程序调用accept()
   → 从全连接队列取出连接

🎭 生活例子:餐厅就餐 🍽️

半连接队列 = 预约登记处
全连接队列 = 等位区

你打电话预约:
"我要预约,2个人"(第1次握手)
服务员:"好的,您贵姓?"(第2次握手)
→ 你的名字进入预约本(半连接队列)

你:"我姓张"(第3次握手)
→ 预约确认,请到等位区(全连接队列)

服务员叫号:
"张先生,您的桌子准备好了"accept())
→ 你从等位区进入餐厅(建立连接)

📊 完整流程

客户端                服务器
  |                     |
  | ①SYN                |
  |-------------------->| 
  |                     | → 进入半连接队列(SYN_RCVD)
  |                     |   [连接1(未完成)]
  |                     |
  | ②SYN+ACK            |
  |<--------------------|
  |                     |
  | ③ACK                |
  |-------------------->|
  |                     | → 从半连接队列移除
  |                     |   移到全连接队列(ESTABLISHED)
  |                     |   [连接1(已完成)]
  |                     |
  |                     | → 应用程序accept()
  |                     |   从全连接队列取出
  |                     |
  | 开始通信             |
  |<====================|

⚠️ 队列满了会怎样?

半连接队列满

场景:SYN Flood攻击

攻击者:疯狂发SYN,不回复ACK
服务器:半连接队列满了!

[SYN1][SYN2][SYN3]...[SYN100](满了!)

新客户端:发送SYN
服务器:❌ 队列满了,丢弃SYN或发送RST

正常用户无法连接!💀

全连接队列满

场景:应用程序accept()太慢

半连接 → 全连接 → 全连接 → 全连接(满了!)
         [C1][C2][C3]...[C100]

应用程序:处理太慢,来不及accept()
服务器:全连接队列满了!

新连接完成第3次握手:
服务器:❌ 队列满了
- 方式1:丢弃ACK(客户端会重传)
- 方式2:发送RST(拒绝连接)

💻 Java代码示例

设置队列大小

// 创建ServerSocket时指定backlog(全连接队列大小)
ServerSocket serverSocket = new ServerSocket(8080, 50);
//                                              端口  ↑backlog=50

// backlog含义:
// - 全连接队列的最大长度
// - 默认值:50(Java)
// - 实际大小还受操作系统限制

System.out.println("服务器启动,backlog=50");

队列满的现象

// 服务器:accept()很慢
ServerSocket serverSocket = new ServerSocket(8080, 10); // 小队列

while (true) {
    Socket socket = serverSocket.accept();
    System.out.println("接受连接:" + socket);
    
    // 模拟处理很慢
    Thread.sleep(5000); // 5秒才处理一个
    
    // 如果客户端连接很快,队列会满!
}

// 客户端:疯狂连接
for (int i = 0; i < 20; i++) {
    new Thread(() -> {
        try {
            Socket socket = new Socket("localhost", 8080);
            System.out.println("连接成功");
        } catch (IOException e) {
            System.out.println("连接失败:" + e.getMessage());
            // 队列满时会连接失败
        }
    }).start();
}

查看队列状态(Linux)

# 查看TCP队列统计
ss -lnt
# 输出:
# State    Recv-Q Send-Q Local Address:Port
# LISTEN   0      50     *:8080
#          ↑      ↑
#   当前队列大小  队列最大值

# Recv-Q:当前全连接队列中的连接数
# Send-Q:队列最大容量(backlog)

# 查看半连接队列
netstat -s | grep SYN
# 输出:
# 12345 SYNs to LISTEN sockets dropped
#(半连接队列满导致的SYN丢弃)

🐛 常见面试题

Q1:什么是半连接队列和全连接队列?

答案:

半连接队列(SYN Queue):
- 存储处于SYN_RCVD状态的连接
- 已收到SYN,发送了SYN+ACK
- 等待客户端的第3次握手ACK

全连接队列(Accept Queue):
- 存储处于ESTABLISHED状态的连接
- 三次握手已完成
- 等待应用程序accept()取走

流程:
客户端SYN → 半连接队列
客户端ACK → 全连接队列
应用accept() → 取出连接

生活例子:
半连接:预约登记(握手中)
全连接:等位区(握手完成)
accept():叫号入座

Q2:如何防御SYN Flood攻击?

答案:

SYN Flood攻击:
攻击者发送大量SYN,不回复ACK
导致半连接队列满,正常用户无法连接

防御方案:

1. SYN Cookie
   - 不分配半连接队列资源
   - 在SYN+ACK中编码连接信息
   - 收到ACK后验证Cookie
   - 验证通过再建立连接
   Linux: net.ipv4.tcp_syncookies = 1

2. 增加半连接队列大小
   Linux: net.ipv4.tcp_max_syn_backlog = 2048

3. 减少SYN+ACK重传次数
   Linux: net.ipv4.tcp_synack_retries = 1
   (默认5次,改为1次)

4. 缩短超时时间
   快速回收半连接队列资源

5. 使用防火墙/IDS
   检测和过滤异常SYN流量

Q3:全连接队列满了怎么办?

答案:

现象:
- 客户端connect()超时或被拒绝
- 服务器日志:Connection refused
- netstat看到队列满

原因:
1. backlog设置太小
2. 应用程序accept()太慢
3. 连接数突增

解决方案:

1. 增大backlog
   ServerSocket server = new ServerSocket(port, 1024);

2. 优化应用程序
   - accept()后立即交给线程池处理
   - 不要在accept()循环中做耗时操作

3. 使用线程池快速accept()
   ExecutorService executor = Executors.newFixedThreadPool(100);
   while (true) {
       Socket socket = serverSocket.accept();
       executor.submit(() -> handle(socket));
   }

4. 调整系统参数(Linux)
   net.core.somaxconn = 1024
   (系统级别的队列上限)

🎓 总结

两个队列的关键点:

  1. 半连接队列:SYN_RCVD状态,握手中
  2. 全连接队列:ESTABLISHED状态,握手完成
  3. 队列满:SYN Flood攻击或accept()太慢
  4. 防御:SYN Cookie、增大队列、快速accept()

记忆口诀

半连接,握手中 🤝
全连接,握手成 ✅
队列满,拒新客 🚫
快accept,解拥挤 ⚡

文档创建时间:2025-10-31
作者:AI助手 🤖