simultaneous connect: 同时open tcp

去掉这几行代码后会调用tcp_data_queue 发送ack等数据
普通 connect: CLOSED → SYN_SENT → ESTABLISHED 服务端 accept: LISTEN → SYN_RECV → ESTABLISHED simultaneous connect: CLOSED → SYN_SENT ↓ 收到 SYN SYN_RECV ↓ 收到 SYN+ACK ESTABLISHED
我们把两个主机(A 和 B)同时发起连接的过程拆解一下,你就明白这个状态是怎么来的了:
-
初始状态:A 和 B 都是
CLOSED。 -
同时发起:
-
A 调用
connect(),发送 SYN (Seq=100)。A 进入SYN_SENT状态。 -
B 调用
connect(),发送 SYN (Seq=200)。B 进入SYN_SENT状态。
-
-
SYN 包在网络中“擦肩而过”。
-
收到对方的 SYN(关键点来了!):
-
A 在处于
SYN_SENT状态时,收到了 B 发来的 SYN (Seq=200)。 -
根据 TCP 协议(RFC 793),A 意识到:“咦,我也想连你,你正好也想连我?”
-
A 必须对 B 的 SYN 进行确认。于是 A 发送 SYN+ACK (Seq=100, Ack=201)。
-
此时,A 的状态从
SYN_SENT变为SYN_RCVD(即 Linux 中的TCP_SYN_RECV)。
-
-
建立连接:
-
B 也会经历同样的过程,变成
SYN_RCVD并发送 SYN+ACK。 -
当 A 收到 B 的 SYN+ACK 时,A 回复 ACK,状态变为
ESTABLISHED
-
但是tcp sock变为ESTABLISHED 后;在 TCP 状态从 TCP_SYN_RECV 切换到 TCP_ESTABLISHED 时,即使是同时连接的情况,发送一个 ACK(会被视为 DUPACK 或 DSACK)也是可以接受的,甚至是预期的行为。因此,之前的“优化”是不必要的,且弊大于利。
如果不发送ack;此时会出现:
TCP Fast Open 允许在三次握手的 ACK 包中携带数据。
-
问题:如果第3个 ACK 包含数据,且连接在收到数据前已经被
accept(),之前添加的goto consume逻辑会导致这些数据被忽略。 -
后果:数据没有被处理,也就不会被确认(ACKed),导致 TFO 功能异常。
Simultaneous Connect),为什么要检查 if (sk->sk_socket)?
它的真实意图是区分“主动打开(Active Open)”和“被动打开(Passive Open)”。
-
主动方 (Client):
-
是你主动调用的
socket()和connect()。 -
所以在握手开始前,你的
struct sock就已经和struct socket绑好了。 -
特征:
sk->sk_socket不为空。
-
-
被动方 (Server):
-
服务器收到 SYN 包时,内核会在底层悄悄创建一个新的
struct sock(子 socket)来处理这个连接请求。 -
在三次握手完成并被用户调用
accept()取走之前,这个临时的子 socket 往往还没有完全分配好对应的上层struct socket(或者说还没跟文件描述符绑定)。 -
特征:在握手早期的某些阶段,其
sk->sk_socket可能是 NULL 或者处于特殊状态。
-

浙公网安备 33010602011771号