概述

TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。在TCP连接的生命周期中,连接会经历不同的状态,这些状态反映了连接的当前状态和可执行的操作。

TCP连接状态总览

TCP连接主要有以下几种状态:

  • CLOSED: 初始状态,表示连接已关闭
  • LISTEN: 服务器等待连接请求
  • SYN_SENT: 客户端已发送SYN包,等待服务器响应
  • SYN_RECEIVED: 服务器收到SYN包,已发送SYN+ACK包
  • ESTABLISHED: 连接已建立,可以传输数据
  • FIN_WAIT_1: 主动关闭方发送FIN包,等待ACK
  • FIN_WAIT_2: 主动关闭方收到ACK,等待对方FIN包
  • CLOSE_WAIT: 被动关闭方收到FIN包,等待应用层关闭
  • CLOSING: 双方同时关闭连接,这是一个相对罕见的状态
  • LAST_ACK: 被动关闭方发送FIN包,等待ACK
  • TIME_WAIT: 主动关闭方等待2MSL时间

连接建立过程(三次握手)

状态转换流程

CLOSED → LISTEN → SYN_RECEIVED → ESTABLISHED
   ↑         ↓           ↓           ↓
   └─────────┴───────────┴───────────┘

详细过程

  1. CLOSED → LISTEN

    • 服务器调用listen()函数
    • 进入LISTEN状态,等待客户端连接请求
  2. LISTEN → SYN_RECEIVED

    • 服务器收到客户端的SYN包
    • 发送SYN+ACK包
    • 进入SYN_RECEIVED状态
  3. SYN_RECEIVED → ESTABLISHED

    • 服务器收到客户端的ACK包
    • 连接建立完成
    • 进入ESTABLISHED状态

三次握手时序图

Client Server 连接建立过程(三次握手) SYN (seq=x) SYN_SENT LISTEN SYN+ACK (seq=y, ack=x+1) ESTABLISHED SYN_RECEIVED ACK (ack=y+1) ESTABLISHED ESTABLISHED Client Server

连接断开过程(四次挥手)

状态转换流程

主动关闭方:ESTABLISHED → FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED
                ↓           ↓           ↓
被动关闭方:ESTABLISHED → CLOSE_WAIT → LAST_ACK → CLOSED

详细过程

主动关闭方(可以是客户端或服务器)
  1. ESTABLISHED → FIN_WAIT_1

    • 主动关闭方调用close()函数
    • 发送FIN包
    • 进入FIN_WAIT_1状态
  2. FIN_WAIT_1 → FIN_WAIT_2

    • 收到对方的ACK包
    • 进入FIN_WAIT_2状态
  3. FIN_WAIT_2 → TIME_WAIT

    • 收到对方的FIN包
    • 发送ACK包
    • 进入TIME_WAIT状态
  4. TIME_WAIT → CLOSED

    • 等待2MSL时间
    • 进入CLOSED状态
被动关闭方(可以是服务器或客户端)
  1. ESTABLISHED → CLOSE_WAIT

    • 收到对方的FIN包
    • 发送ACK包
    • 进入CLOSE_WAIT状态
  2. CLOSE_WAIT → LAST_ACK

    • 应用层调用close()函数
    • 发送FIN包
    • 进入LAST_ACK状态
  3. LAST_ACK → CLOSED

    • 收到对方的ACK包
    • 进入CLOSED状态

四次挥手时序图

Active Passive 连接断开过程(四次挥手) FIN (seq=u) FIN_WAIT_1 ESTABLISHED ACK (ack=u+1) FIN_WAIT_2 CLOSE_WAIT FIN (seq=v) TIME_WAIT LAST_ACK ACK (ack=v+1) TIME_WAIT CLOSED 等待2MSL时间 CLOSED Active Passive

状态转换图

服务器调用listen()
收到SYN
收到ACK
客户端调用connect()
收到SYN+ACK
主动关闭
收到FIN
收到ACK
收到FIN
收到FIN
应用层关闭
收到ACK
收到ACK
2MSL超时
异常关闭
CLOSED
LISTEN
SYN_RECEIVED
ESTABLISHED
SYN_SENT
FIN_WAIT_1
CLOSE_WAIT
FIN_WAIT_2
CLOSING
TIME_WAIT
LAST_ACK
主动关闭方路径
被动关闭方路径

重要状态说明

ESTABLISHED

  • 连接已建立,可以双向传输数据
  • 这是TCP连接的正常工作状态
  • 可以发送和接收数据

TIME_WAIT

  • 主动关闭方必须等待2MSL时间
  • MSL(Maximum Segment Lifetime)是报文段在网络中的最大生存时间
  • 通常为2分钟
  • 目的:
    • 确保最后的ACK包能够到达对方
    • 让旧连接的分组在网络中消失
    • 避免新连接收到旧连接的数据

CLOSE_WAIT

  • 被动关闭方等待应用层关闭连接
  • 此时仍可以发送数据
  • 如果应用层不及时关闭,可能导致连接长时间处于此状态

CLOSING

  • 出现原因:双方几乎同时调用close()函数,导致同时发送FIN包
  • 状态描述:主动关闭方在FIN_WAIT_1状态下收到对方的FIN包
  • 转换过程:FIN_WAIT_1 → CLOSING → TIME_WAIT → CLOSED
  • 特点
    • 这是一个相对罕见的状态,因为需要精确的时间同步
    • 双方都进入了关闭过程,但都还没有收到对方的ACK
    • 当收到对方的ACK后,会转换到TIME_WAIT状态
  • 实际场景
    • 网络延迟极低的环境下,双方同时发起关闭
    • 某些应用协议中,客户端和服务器约定同时关闭连接
    • 网络异常情况下,双方都认为需要关闭连接
协议栈支持情况
  • RFC 793标准:TCP协议标准文档中明确定义了CLOSING状态
  • 主流操作系统:Linux、Windows、macOS等操作系统的TCP/IP协议栈都支持CLOSING状态
  • 网络设备:路由器、交换机等网络设备也支持此状态
CLOSING状态的识别特征
  1. 包序列特征

    • 双方几乎同时发送FIN包
    • FIN包的序列号接近
    • 时间间隔极短(通常<1ms)
  2. 状态转换特征

    • 连接从FIN_WAIT_1直接转换到CLOSING
    • 跳过FIN_WAIT_2状态
    • 快速转换到TIME_WAIT状态
  3. 网络环境特征

    • 低延迟网络环境
    • 双方应用层同时调用close()
    • 网络拥塞或异常情况
实际测试方法
# 创建测试脚本,模拟同时关闭
#!/bin/bash
# 客户端和服务器同时关闭连接测试
nc -l 8080 &
SERVER_PID=$!
sleep 1
nc localhost 8080 &
CLIENT_PID=$!
sleep 1
kill $SERVER_PID $CLIENT_PID

# 监控TCP状态变化
watch -n 0.1 'ss -tan | grep -E "(FIN_WAIT|CLOSING|TIME_WAIT)"'

TCP同时打开(Simultaneous Open)

概念说明

TCP同时打开是指两个应用程序同时向对方发起连接请求,而不是传统的客户端-服务器模式。这是TCP协议的一个重要特性,允许两个对等方同时建立连接。

同时打开的状态转换过程

状态转换流程
CLOSED → SYN_SENT → SYN_RECEIVED → ESTABLISHED
   ↑         ↓           ↓           ↓
   └─────────┴───────────┴───────────┘
详细过程
  1. 双方同时发送SYN包

    • 两个应用程序同时调用connect()函数
    • 双方都进入SYN_SENT状态
    • 双方都发送SYN包给对方
  2. 双方收到对方的SYN包

    • 双方都收到对方的SYN包
    • 双方都进入SYN_RECEIVED状态
    • 双方都发送SYN+ACK包给对方
  3. 双方收到对方的SYN+ACK包

    • 双方都收到对方的SYN+ACK包
    • 双方都发送ACK包给对方
    • 双方都进入ESTABLISHED状态

同时打开时序图

A B TCP同时打开过程 SYN (seq=x) SYN_SENT SYN_SENT SYN (seq=y) SYN_RECEIVED SYN_RECEIVED SYN+ACK (seq=x+1, ack=y+1) SYN_RECEIVED SYN_RECEIVED SYN+ACK (seq=y+1, ack=x+1) SYN_RECEIVED SYN_RECEIVED ACK (ack=y+1) ESTABLISHED ESTABLISHED ACK (ack=x+1) ESTABLISHED ESTABLISHED A B

协议栈支持情况

标准支持
  • RFC 793:TCP协议标准文档中明确定义了同时打开
  • RFC 1122:进一步规范了同时打开的行为
  • 所有主流操作系统:Linux、Windows、macOS等都支持同时打开
实现特点
  1. 状态机支持:TCP状态机完全支持同时打开的状态转换
  2. 序列号处理:正确处理双方SYN包的序列号
  3. 连接建立:最终建立两个独立的连接(每个方向一个)

实际应用场景

1. P2P应用
  • BitTorrent:对等节点之间建立连接
  • Skype:点对点通信
  • 游戏网络:玩家之间的直接连接
2. 分布式系统
  • 集群通信:节点之间的双向通信
  • 负载均衡:服务器之间的健康检查
  • 数据同步:双向数据复制
3. 网络协议
  • BGP:边界网关协议中的对等连接
  • OSPF:开放最短路径优先协议
  • IS-IS:中间系统到中间系统协议

与普通连接的区别

普通连接(三次握手)
  • 客户端发送SYN → 服务器发送SYN+ACK → 客户端发送ACK
  • 明确的客户端-服务器角色
  • 单向连接建立
同时打开(四次握手)
  • 双方同时发送SYN → 双方同时发送SYN+ACK → 双方同时发送ACK
  • 对等方角色
  • 双向连接建立

注意事项

  1. 端口冲突:双方不能使用相同的端口
  2. 防火墙:需要允许双向连接
  3. NAT穿透:可能需要特殊处理
  4. 连接管理:需要正确管理两个方向的连接

常见问题与解决方案

1. 大量TIME_WAIT状态

问题: 出现大量TIME_WAIT状态的连接
原因: 主动关闭连接(可能是客户端或服务器)
解决:

  • 使用SO_REUSEADDR选项
  • 调整tcp_tw_reuse参数
  • 让另一方主动关闭连接

2. 大量CLOSE_WAIT状态

问题: 出现大量CLOSE_WAIT状态的连接
原因: 应用层没有及时关闭连接
解决:

  • 检查应用代码,确保正确关闭连接
  • 设置合适的超时时间
  • 使用连接池管理连接

3. 连接建立失败

问题: 无法建立连接
可能原因:

  • 服务器未启动或端口未开放
  • 防火墙阻止连接
  • 网络配置问题

TCP/IP 常见参数确认

TCP最大报文段长度MSS

ip link show 查看其中MTU的值

  • MTU = 1500字节
  • IP头部 = 20字节
  • TCP头部 = 20字节
  • MSS = 1500 - 20 - 20 = 1460字节

PPPoE环境:

  • MTU = 1492字节
  • IP头部 = 20字节
  • TCP头部 = 20字节
  • MSS = 1492 - 20 - 20 = 1452字节

TCP的报文最大生存时间MSL

  • RFC标准定义
    RFC 793:MSL建议值为2分钟
    RFC 1122:MSL建议值为2分钟
    实际实现:大多数系统使用60秒

  • 不同操作系统的MSL值
    Linux 60秒 120秒
    Windows 120秒 240秒
    macOS 60秒 120秒
    FreeBSD 60秒 120秒

  • 查看TCP相关时间参数
    cat /proc/sys/net/ipv4/tcp_fin_timeout
    cat /proc/sys/net/ipv4/tcp_keepalive_time
    cat /proc/sys/net/ipv4/tcp_keepalive_intvl
    cat /proc/sys/net/ipv4/tcp_keepalive_probes

  • 查看TIME_WAIT相关参数
    cat /proc/sys/net/ipv4/tcp_tw_reuse
    cat /proc/sys/net/ipv4/tcp_tw_recycle
    cat /proc/sys/net/ipv4/tcp_max_tw_buckets

/proc/net/tcp

/proc/net/tcp是Linux内核提供的一个虚拟文件,用于显示当前系统中所有TCP连接的状态信息。这个文件是实时更新的,反映了内核中TCP连接表的当前状态。

  • 字段含义表
字段 含义 说明
sl socket序号 内核中socket的序号
local_address 本地地址 格式:IP:端口(十六进制)
rem_address 远程地址 格式:IP:端口(十六进制)
st 连接状态 TCP连接状态码
tx_queue 发送队列 发送缓冲区中的数据量
rx_queue 接收队列 接收缓冲区中的数据量
tr 定时器 定时器相关信息
tm->when 超时时间 超时时间戳
retrnsmt 重传次数 重传计数器
uid 用户ID 创建连接的用户ID
timeout 超时值 连接超时时间
inode inode号 对应的socket inode号
  • TCP状态码对照表
状态码 状态名称 说明
01 ESTABLISHED 连接已建立
02 SYN_SENT 客户端发送SYN包
03 SYN_RECV 服务器收到SYN包
04 FIN_WAIT1 主动关闭方发送FIN包
05 FIN_WAIT2 主动关闭方收到ACK包
06 TIME_WAIT 主动关闭方等待2MSL
07 CLOSE 连接已关闭
08 CLOSE_WAIT 被动关闭方收到FIN包
09 LAST_ACK 被动关闭方发送FIN包
0A LISTEN 服务器监听状态
0B CLOSING 双方同时关闭连接

TCP交互的FIN_Wait_2时间要求是多少

FIN_WAIT_2是TCP连接关闭过程中的一个状态,表示主动关闭方已经发送了FIN包并收到了对方的ACK确认,正在等待对方发送FIN包。

标准时间要求
RFC标准:没有明确规定FIN_WAIT_2的超时时间
实际实现:大多数系统使用2分钟(120秒)
Linux默认:通常为60秒

查看TCP FIN超时时间
cat /proc/sys/net/ipv4/tcp_fin_timeout

是否支持TCP 2*MSL of RTO

tcp_rto_min:RTO的最小值,防止RTO过小
tcp_rto_max:RTO的最大值,防止RTO过大
tcp_retries2:数据包重传的最大次数
tcp_timestamps:是否启用TCP时间戳选项
主要参数说明

参数 路径 说明 默认值
tcp_rto_min /proc/sys/net/ipv4/tcp_rto_min RTO最小值(毫秒) 200
tcp_rto_max /proc/sys/net/ipv4/tcp_rto_max RTO最大值(毫秒) 120000
tcp_retries2 /proc/sys/net/ipv4/tcp_retries2 重传次数 15
tcp_timestamps /proc/sys/net/ipv4/tcp_timestamps 时间戳选项 1
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐