Posix API与网络协议栈第一篇

一、面试中协议栈常问的点

1.tcp三次握手的过程?

客户端------>服务端:

将Syn位置1,发送自己的初始序列号seqnum,此位随机值,表示请求连接,并告知服务器自己的初始序列号。

服务端------>客户端:

将Syn和ACK位置1,将收到的客户端初始序列号加1作为确认号Acknum,和初始序列号seqnum发送到客户端,表示同意连接,并发送自己的初始序列号。

客户端------>服务器:

将ACK置1,将服务端发送过来的初始序列号加1,作为确认号发送到服务端,表示确认服务器序列号,连接正式建立。

其中syn只在第一次和第二次握手中被置1,syn标志的作用是再握手阶段用于初始序列号,交换双方的seq值,第三次握手客户端只需发送确认号,让客户端知道自己能够接收,同理ack只在第二次和第三次握手中置1。

三次握手过程中服务端的状态:

1.初始状态:LISTEN

  • 服务器调用listen()后进入LISTEN状态,等待客户端的SYN报文。

  • 关键行为:监听指定端口,准备接受连接请求。

2.收到SYN后:SYN_RCVD

  • 当服务器收到客户端的SYN报文(第一次握手),会回复SYN+ACK(第二次握手),并进入SYN_RCVD状态。

  • 含义 :已收到客户端的连接请求,正在等待客户端的最终ACK确认。

  • 风险:此状态下服务器会为连接分配资源(如半连接队列),可能遭受SYN洪泛攻击(SYN Flood)

  • SYN泛洪攻击:

    攻击原理

  • 攻击者发送大量伪造源 IP 的 SYN 报文,但不回复第三次握手的 ACK

  • 服务器在 SYN_RCVD 状态下维护半连接队列,资源被耗尽,无法响应正常请求。

  • 防御措施:

  • SYN Cookies (Linux 默认启用):

    不存储半连接状态,而是通过加密算法生成 SYN+ACK 的序列号,验证合法客户端的 ACK

    bash

  • 限制半连接队列大小

    复制代码
    sysctl -w net.ipv4.tcp_max_syn_backlog=2048
  • 防火墙/IP 黑名单 :过滤高频 SYN 请求。

3.收到ACK后:ESTABLISHED

  • 服务器收到客户端的ACK报文(第三次握手)后,确认连接建立,状态变为ESTABLISHED

  • 含义:双方已同步序列号,可以开始正常数据传输。

关键注意事项

  1. 半连接队列(SYN Queue)

    • SYN_RCVD状态下,连接会被放入半连接队列(未完全建立的连接队列)。

    • 若队列满,新SYN可能被丢弃(触发客户端重传)。

  2. 全连接队列(Accept Queue)

    • 进入ESTABLISHED后,连接被移至全连接队列,等待服务器调用accept()处理。

    • 若队列满且未及时accept(),可能导致客户端认为连接已建立,但服务器无法响应。

  3. 超时处理

    • 若服务器未收到客户端的ACK(第三次握手),会重传SYN+ACK(默认重试次数由系统配置,如Linux的tcp_synack_retries)。

2.TCP四次挥手过程?

假设客户端主动发起关闭,服务端被动关闭:

客户端------>服务端(FIN):

发送FIN=1(终止标志),序列号为seq = u (客户端最后发送的数据序列号加1);

客户端状态:ESTABLISHED------>FIN_WAIT_1(等待服务端确认)。

含义:客户端主动请求关闭连接,但仍能接收服务端的数据。

服务端------>客户端(ACK):

发送ACK报文,ack置1,确认号为u+1;

服务端状态:ESTABLISHED------>CLOSE_WAIT,等待服务端应用层关闭;

客户端状态:FIN_WAIT_1------>FIN_WAIT_2,等待服务端的FIN;

关键点:此时服务端可能还有未发送完的数据。

服务端------>客户端(FIN):

服务端应用层调用close,将FIN置1,发送seq = v,v为最后的数据序列号加1;

服务端状态:CLOSE_WAIT------>LAST_ACK(等待客户端最后确认);

含义:服务端数据发送完毕,等待确认。

客户端------>服务端(ACK):

ACK置1,发送确认号ack = v+1;

客户端状态:FIN_WAIT_2------>TIME_WAIT(等待2MSL后进入CLOSED);

服务端状态:收到ack后进入CLOSED;

作用:确保服务端收到确认,处理可能残余报文。

关键问题解析

1. 为什么需要四次挥手?
  • TCP 是全双工协议,双方需独立关闭各自的通道:

    • 客户端发 FIN 表示不再发送数据,但可接收数据(服务端可能还需发送剩余数据)。

    • 服务端发 FIN 表示数据已发送完毕,双方才完全关闭。

2. TIME_WAIT 状态的作用
  • 等待 2MSL(Maximum Segment Lifetime)

    • 确保最后一个 ACK 能到达服务端(若丢失,服务端会重传 FIN)。

    • 让网络中残留的旧报文失效,避免影响新连接。

  • 默认时长:Linux 中通常为 60 秒。

3. CLOSE_WAIT 状态积压的隐患
  • 若服务端长时间处于 CLOSE_WAIT,可能是代码未调用 close(),导致资源泄漏。

  • 排查方法 :通过 netstat -antp | grep CLOSE_WAIT 检查。

4. 异常场景
  • 服务端不发送 FIN :客户端将永远卡在 FIN_WAIT_2(可通过系统参数如 tcp_fin_timeout 强制超时)。

  • 客户端崩溃 :服务端在 LAST_ACK 状态超时后重传 FIN,最终关闭。

3.超时重传和快速重传

1. 超时重传(Timeout Retransmission)

触发条件
  • 当发送方发送一个数据包后,如果在 RTO(Retransmission Timeout,重传超时时间) 内没有收到对应的 ACK 确认,就会触发超时重传。

  • RTO 计算 :基于 RTT(Round-Trip Time,往返时间)动态调整,通常使用 指数退避(Exponential Backoff) 策略(超时后 RTO 翻倍)。

工作流程
  1. 发送方发送数据包 Seq=1,并启动 重传计时器

  2. 如果 ACK 未在 RTO 时间内到达:

    • 发送方认为数据包丢失,重传该数据包

    • RTO 翻倍(避免网络拥塞时频繁重传)。

  3. 如果仍然没有 ACK,继续重传,直到达到最大重传次数(如 Linux 默认 tcp_retries2=15)。

特点
  • 保守策略 :等待超时后才重传,适用于 严重丢包网络延迟突增 的情况。

  • 效率较低:因为必须等待超时,可能导致传输延迟增加。


2. 快速重传(Fast Retransmit)

触发条件
  • 当发送方 连续收到 3 个重复的 ACK(DupACK) 时,立即重传丢失的数据包,而不必等待超时。

  • 为什么是 3 次?

    • 1~2 次 DupACK 可能是网络乱序(如数据包顺序变化),但 3 次及以上 基本可以判定数据包丢失。
工作流程
  1. 发送方发送数据包 Seq=1, 2, 3, 4, 5

  2. 假设 Seq=2 丢失,接收方收到 Seq=3, 4, 5 时,每次都会回复 ACK=2(期望收到 Seq=2)。

  3. 发送方收到 3 个 ACK=2 ,立即 重传 Seq=2(快速重传)。

  4. 接收方收到 Seq=2 后,回复 ACK=6(确认所有数据)。

特点
  • 快速恢复:比超时重传更快,减少等待时间。

  • 依赖 DupACK:仅适用于部分丢包(如果整个窗口丢失,可能不会触发)。

  • 通常结合快速恢复(Fast Recovery)

    • 重传后,发送方不会直接进入慢启动,而是调整拥塞窗口(cwnd),提高传输效率。

对比总结

机制 触发条件 优点 缺点 适用场景
超时重传 数据包 ACK 超时(RTO) 适用于严重丢包 延迟高,效率低 网络严重拥塞
快速重传 收到 3 个重复 ACK(DupACK) 快速恢复,减少等待时间 依赖部分丢包情况 少量丢包、乱序

实际应用

  • 超时重传 是 TCP 最基础的重传机制,但效率较低。

  • 快速重传 + 快速恢复 是 TCP 优化的重要手段(如 Reno、Cubic 算法 均采用)。

  • 现代 TCP(如 SACK)可以更精确地识别丢失的数据包,减少不必要的重传。


扩展:SACK(Selective Acknowledgment)

  • 允许接收方 明确告知发送方哪些数据包丢失(而不是仅靠 DupACK)。

  • 进一步优化快速重传,减少重传冗余数据。


总结
  • 超时重传:兜底机制,确保数据最终送达,但延迟高。

  • 快速重传:优化机制,减少等待时间,提高传输效率。

  • 两者结合,使 TCP 在保证可靠性的同时,尽量提高传输速度。

4.TCP首部长度,有哪些字段

TCP 首部长度通常为 20 字节(最小长度) ,但如果包含 选项(Options) ,最大可扩展至 60 字节。其结构如下:


1. TCP 首部字段(固定部分,20 字节)

字段名 位数 说明
源端口(Source Port) 16 发送方的端口号(范围:0~65535)。
目的端口(Destination Port) 16 接收方的端口号(如 HTTP=80, HTTPS=443)。
序列号(Sequence Number) 32 当前数据包的第一个字节的编号(用于数据排序和重组)。
确认号(Acknowledgment Number) 32 期望收到的下一个字节的编号(ACK=1 时有效)。
数据偏移(Data Offset) 4 TCP 首部长度(单位:4 字节),最小 5(20 字节),最大 15(60 字节)。
保留(Reserved) 6 保留字段,必须设为 0。
控制标志(Flags) 6 用于控制连接状态(见下表)。
窗口大小(Window Size) 16 接收方的可用缓冲区大小(流量控制,单位:字节)。
校验和(Checksum) 16 校验 TCP 首部和数据部分(防止数据损坏)。
紧急指针(Urgent Pointer) 16 仅当 URG=1 时有效,指向紧急数据的末尾(很少使用)。

2. 控制标志(Flags,6 位)

标志位 名称 说明
URG Urgent 紧急数据标志(需配合 Urgent Pointer 使用)。
ACK Acknowledgment 确认标志(Acknowledgment Number 有效)。
PSH Push 接收方应立即将数据交给应用层(避免缓冲延迟)。
RST Reset 强制断开连接(异常终止)。
SYN Synchronize 同步序列号(用于三次握手建立连接)。
FIN Finish 终止连接(用于四次挥手关闭连接)。

3. TCP 选项(Options,可选,最多 40 字节)

如果 数据偏移(Data Offset)> 5,则包含选项字段,常见选项有:

选项类型 说明
MSS(Maximum Segment Size) 协商最大报文段长度(通常 1460 字节,避免 IP 分片)。
Window Scale(WSOPT) 扩展窗口大小(用于高带宽网络,突破 65535 字节限制)。
SACK(Selective Acknowledgment) 选择性确认,优化重传机制(仅重传丢失的数据包)。
Timestamp(TSOPT) 时间戳,用于计算 RTT(Round-Trip Time)和防止序列号回绕(PAWS)。
NOP(No Operation) 填充选项,用于对齐 4 字节边界。

4. TCP 首部示例


5. 关键字段详解

(1) 数据偏移(Data Offset)

  • 表示 TCP 首部长度 ,单位是 4 字节

  • 最小值 5(20 字节),最大值 15(60 字节)。

  • 例如:

    • Data Offset = 5 → 首部 20 字节(无选项)。

    • Data Offset = 8 → 首部 32 字节(含 12 字节选项)。

(2) 序列号(Sequence Number)和确认号(Acknowledgment Number)

  • 序列号 :当前数据包的第一个字节的编号(随机初始化,防止预测攻击)。

  • 确认号期望收到的下一个字节的编号ACK=1 时有效)。

(3) 窗口大小(Window Size)

  • 用于 流量控制,表示接收方当前可接收的数据量(单位:字节)。

  • 如果窗口为 0,发送方必须暂停传输(避免接收方缓冲区溢出)。


6. 总结

字段 作用
源/目的端口 标识通信的应用程序。
序列号/确认号 保证数据有序和可靠传输。
数据偏移 确定 TCP 首部长度。
控制标志(SYN/ACK/FIN/RST) 管理连接状态(握手、挥手、复位)。
窗口大小 流量控制,防止接收方过载。
校验和 检测数据是否损坏。
选项(MSS/SACK/Timestamp) 优化 TCP 性能(如提高传输效率、减少重传)。

TCP 首部设计兼顾了 可靠性、流量控制、拥塞控制,是现代网络通信的基石。

5.TCP在listen时的参数backlog的意义

backlog 参数在 TCP 协议栈的发展过程中经历了多次调整和优化,其语义和实现方式在不同操作系统和内核版本中有所变化。以下是其演进历程:


1. 早期实现(BSD 4.2,1983年)

  • 初始定义backlog 表示 半连接队列(SYN Queue)和全连接队列(Accept Queue)的总和上限

  • 问题

    • 未严格区分两种队列,导致资源分配不合理。

    • 易受 SYN Flood 攻击(半连接队列被恶意占满)。


2. BSD 4.3(1986年)的改进

  • 分离队列 :明确区分 半连接队列全连接队列

    • 半连接队列:存储 SYN_RCVD 状态的连接。

    • 全连接队列:存储 ESTABLISHED 状态的连接(等待 accept())。

  • backlog 语义 :仅表示 全连接队列的最大长度

  • 新增限制 :半连接队列大小由系统参数单独控制(如 net.ipv4.tcp_max_syn_backlog)。


3. Linux 的演进(1990s~2000s)

(1) Linux 2.2 之前
  • 行为类似 BSDbacklog 控制全连接队列。

  • 问题:高并发场景下队列易溢出。

(2) Linux 2.2+ 的优化
  • 引入 somaxconn

    • 全连接队列的实际大小为 min(backlog, somaxconn)

    • 默认值:somaxconn=128(可通过 /proc/sys/net/core/somaxconn 调整)。

  • 半连接队列独立控制

    • net.ipv4.tcp_max_syn_backlog 定义(默认 256)。

    • 启用 SYN Cookiesnet.ipv4.tcp_syncookies=1)后可动态扩展半连接队列。

(3) Linux 4.3+ 的进一步改进
  • backlog 的弹性扩展

    • 当全连接队列满时,内核可能临时扩大队列(避免直接丢弃连接)。
  • 多队列支持

    • 在多核环境下,采用 per-CPU 队列减少锁竞争。
相关推荐
威视锐科技1 小时前
软件定义无线电36
网络·网络协议·算法·fpga开发·架构·信息与通信
二进制人工智能2 小时前
【QT5 网络编程示例】TCP 通信
网络·c++·qt·tcp/ip
落笔画忧愁e4 小时前
VRRP协议
网络·智能路由器
iOS技术狂热者5 小时前
使用抓包大师(sniff master)进行手机端iOS抓包的配置步骤
websocket·网络协议·tcp/ip·http·网络安全·https·udp
卓应5 小时前
2025年华为H31-831题库
网络·华为
山楂树の6 小时前
计算机网络 TCP/IP参考模型
网络·tcp/ip·计算机网络
卓应8 小时前
2025年华为HCIP题库分享
网络·华为·智能路由器
CryptoPP9 小时前
基于WebSocket的金融数据实时推送系统架构设计对接多国金融数据API
websocket·网络协议·金融·系统架构·区块链
WoTrusSSL9 小时前
SSL证书如何保障人脸识别系统安全?
网络协议·系统安全·ssl
榆榆欸10 小时前
7.从Server到Acceptor,优化Reactor模式的实现
linux·服务器·网络