news 2026/10/13 8:52:18

连不上之前发生了什么:一次 TCP 连接怎么建立

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
连不上之前发生了什么:一次 TCP 连接怎么建立

授权与合规声明
本文全部操作对象均为自建隔离靶场(本机容器或隔离虚拟机),涉及安全测试的环节必须以取得合法授权为前提。未经授权的渗透测试违反《中华人民共和国网络安全法》与《刑法》相关条款,须承担相应法律责任。本文只讲环境配置、版本对照与靶场隔离,不含任何攻击步骤、利用载荷与绕过手法,请勿将文中环境指向任何非自有系统。

本文引用的规范原文取自 RFC 9293(TCP 现行标准文本),核验日期为 2026-10-13,英文原句逐字保留、不加改动。

一、三种"连不上",其实是同一段过程停在了三个位置

1.1 界面上看到的三种样子

刚开始用抓包工具的人,最常撞到的"连不上"有三种:

  • 只看到几个"空包",然后页面正常打开了。抓包窗口里先是几行不带内容的东西,之后才是真正带数据的请求。
  • 连接被拒绝。几乎不等待,瞬间就结束了。
  • 一直转圈,最后超时。界面卡很久。

这三者放在一起毫无共同点:一个快得没有过程,一个慢得看不到头,还有一个干脆什么都不显示。但背后是同一件事——一次连接的建立过程,走到了不同的位置。你以为在看三种毛病,其实是在看同一个过程的三张快照。

1.2 先把这段过程的名字立起来

规范给这段过程起了名字。RFC 9293 §3.5 的第一句就是它的定义(表 A 第 1 行):

The “three-way handshake” is the procedure used to establish a connection.

即:"三次握手"就是用来建立连接的那个过程。这句话把位置摆正了——“连不上"不是"连接坏了”,而是"建立过程没有走完";既然是过程,就存在"走到哪一步"这个问题。本文的支点就是接下来这句话:连接不是"打开一条管道",而是双方各自维护一份状态;几段交互之后,两份状态才对得上。

1.3 本文的边界

先把不写的列清楚,免得在错的方向上花时间:

  • 本文不写任何扫描、探测与连通性测试类命令。判断某个地址、某个端口上有没有东西在等连接,是另一件事,本文只解释状态。
  • 本文不写抓包样例里的报文字节,也不写各字段在报文里的排列顺序。
  • 本文不写"如何造出半个连接"这类操作。"同时打开"只在"规范承认它是正常路径"这个层面出现(第 5 章)。
  • 不写报文形态(某个应用层协议各版本的报文长什么样)、不写域名解析、不写抓包工具的配置;这三条各自是一条独立的轴。

还有一条边界一次说完:卡到超时,也可能是路上的设备把包丢掉了。中间有没有防火墙一类的设备参与、按什么规则放行,属于另一条轴,本文只用这一句点到,不展开任何出入站规则。

本章可以带走的一句:三种"连不上"不是三种毛病,而是同一段建立过程停在了三个不同位置;先把观察方式从"这句话什么意思"换成"这段过程走到哪一步",排障才有路线可走。

二、连接到底是什么:两份状态,而不是一条管道

2.1 "管道"这个比喻漏掉了最关键的一件事

把连接说成"两端之间有一条管道",听起来直观,但它漏掉了关键一点:这条"管道"里没有任何一处被叫管道的东西,有的只是两边各自的记录。

RFC 9293 §3.3.1 把这件事写得很直白(表 A 第 4 行):

We conceive of these variables being stored in a connection record called a Transmission Control Block or TCB.

也就是:这些变量被设想成放在一份连接记录里,它叫Transmission Control Block,简称TCB。规范紧接着交代了记录里存了什么(表 A 第 5 行):

Among the variables stored in the TCB are the local and remote IP addresses and port numbers

——本地与远端的 IP 地址和端口号都在里面,此外还有序号相关变量、缓冲区指针等。

于是"连接"的真实含义是:**两端各自有一份 TCB,两份 TCB 里的变量互相对得上。**日常排障里习惯把"本地地址+本地端口+远端地址+远端端口"这四项叫四元组(通行叫法,不是规范原话);某一侧找不到匹配的那份记录,对它来说这条连接就不存在。

2.2 十一个状态,其中有一个是"虚构"的

只有记录还不够,还要知道这份记录现在处于什么阶段。规范把阶段排了出来(表 A 第 2 行):

The states are: LISTEN, SYN-SENT, SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT, and the fictional state CLOSED.

一共十一个,其中最后一个用的是"虚构"这个词。规范自己解释了为什么(表 A 第 3 行):

CLOSED is fictional because it represents the state when there is no TCB, and therefore, no connection.

这句值钱的地方在于:**“没有连接"并不是一种状态,而是"没有这条记录”。**某一侧对某个四元组说"它是 CLOSED",真正表达的是"我这里没有对应的 TCB"。由此能推出一条很容易忽略的结论:在那一侧看来,"刚关掉"和"从来没建立过"是同一件事。第 6 章讲"连接被拒绝"时要用到它。

状态一句话容易混的地方
LISTEN在等连接请求等的是"任意远端",不是某个特定对端(第 3 章)
SYN-SENT请求已发出,等一个匹配的请求回来是主动发起的一侧
SYN-RECEIVED请求既收到也发出过,在等确认不专属于应答方(第 5 章)
ESTABLISHED连接已经打开,数据可以交给用户数据传输阶段的正常状态
FIN-WAIT-1、FIN-WAIT-2、CLOSE-WAIT、CLOSING、LAST-ACK、TIME-WAIT关闭过程里的六个状态都属于关闭阶段,本文不展开
CLOSED虚构态:没有 TCB,也就没有连接不是"关掉了",是"没有这份记录"

2.3 两份状态是各自变的,所以"不同步"是常态

既然状态存在各自的记录里,两边的状态就不是同一个东西。本侧进了SYN-SENT(请求已经发出去了),对端此刻可能什么都还没收到;也可能它早就在LISTEN上等着。同一时刻两边记的状态不一样,不是异常,而是常态——因为包在路上。所以每一步都要先问一句:你看的是哪一侧的状态?

下面这段用来在本机看"记录"长什么样,只是只读地把状态列出来,不做任何探测。

⚠️代码待验证

# Linux:列出所有 TCP 连接及其状态列ss-tan# macOS:没有 ss,用 netstat 看同一类信息netstat-an-ptcp

本章可以带走的一句:连接不是一条管道,而是两端各自的一份 TCB 记录;十一个状态里CLOSED是规范明说的虚构态,因为它指的是"没有 TCB",而不是"有一种叫关闭的状态"。

三、三步各做一件事

3.1 四个状态各自的定义

规范对每个状态的说明只有一两行,但逐条都能对上界面现象。下面四条取自 §3.3.2,逐字保留(表 A 第 6–9 行):

LISTEN - represents waiting for a connection request from any remote TCP peer and port.

SYN-SENT - represents waiting for a matching connection request after having sent a connection request.

SYN-RECEIVED - represents waiting for a confirming connection request acknowledgment after having both received and sent a connection request.

ESTABLISHED - represents an open connection, data received can be delivered to the user. The normal state for the data transfer phase of the connection.

LISTEN的定义里有一个词最容易被读快:anyremote TCP peer and port——等的是任意远端的连接请求。所以"有人在LISTEN"的含义是"这里有一个进程在等连接请求",而不是"它认识你"。这个区别在第 6 章会直接决定怎么读"被拒绝"。

3.2 三步到底在同步什么:各自的初始序号

三段交互不是为了"打个招呼"。§3.4.1 写明了要同步的到底是什么(表 A 第 10 行):

The synchronization requires each side to send its own initial sequence number and to receive a confirmation of it in acknowledgment from the remote TCP peer. Each side must also receive the remote peer’s initial sequence number and send a confirming acknowledgment.

这其实是四件事:**我发我的序号、我确认你的、你发你的、你确认我的。**规范紧接着说明了为什么最后叫"三步"(表 A 第 11 行):

Because steps 2 and 3 can be combined in a single message this is called the three-way (or three message) handshake (3WHS).

即:**四件事里有两件可以合并到同一条消息里,于是四条变成了三条。**所以"三步"不是一个刻意挑选的数字,而是合并之后的自然结果——第 4 章问"为什么两步不够"时,答案就落在"少的到底是哪一件事"上。

3.3 主动打开与被动打开:发起方式只有两种

发起连接这件事,规范只分了两种方向。§3.3.2 的措辞(表 A 第 12 行):

A passive OPEN request means that the process wants to accept incoming connection requests, in contrast to an active OPEN attempting to initiate a connection.

一种是被动打开:进程想要接受进来的连接请求,走到LISTEN去等;另一种是主动打开:进程尝试发起一个连接,走到SYN-SENT去等回音。一端在LISTEN、另一端在SYN-SENT——**这就是"看起来只有一条线"的过程里,两份记录在各自变化的样子。**下面这段用来把"状态在变"看出来,同样只读本地状态。

⚠️代码待验证

# 一个终端里每隔一秒列一次 TCP 连接状态,连续看几秒whiletrue;dodate;ss -tan;sleep1;done# macOS 上把 ss 换成 netstatwhiletrue;dodate;netstat-an-ptcp;sleep1;done
步骤发出的一方这一步在做的事两侧状态怎么变
第一步主动打开的一侧发出自己的初始序号发起侧:无记录 →SYN-SENT;应答侧仍停在原处
第二步被动打开的一侧确认对方的序号,同时报出自己的序号应答侧:LISTEN→SYN-RECEIVED
第三步主动打开的一侧确认对方的序号发起侧先到ESTABLISHED;应答侧收到后也到ESTABLISHED

本章可以带走的一句:三步握手里"三步"只是合并的结果——本来要同步四件事(我发我的序号、我确认你的、你发你的、你确认我的),其中两件能合并成一条消息;而LISTEN等的是任意远端,不是某个特定对端。

四、为什么是三步:两步不够,因为"旧包"当场认不出来

4.1 规范里最直接的那一句

如果只允许一个包出去、一个包回来,会省掉一次往返。规范解释了为什么不行。§3.4.1 这一段是全文的支点(表 A 第 13 行):

A 3WHS is necessary because sequence numbers are not tied to a global clock in the network, and TCP implementations may have different mechanisms for picking the ISNs. The receiver of the first SYN hasno way of knowing whether the segment was an old one or not, unless it remembers the last sequence number used on the connection (which is not always possible), and so itmust ask the sender to verify this SYN.

拆成三层意思:

  • 前提一:序号不挂在网络里的某个全局时钟上;各实现挑选初始序号的机制也可以不一样。
  • 前提二:所以收到第一个 SYN 的那一侧,除非它记得这条连接上一次用过的序号,否则没有别的办法判断这个段是不是旧的;而"记得"这件事不是总能做到。
  • 结论:于是它必须请发送方来确认这个 SYN。

因果链很干净:不是"对方认不出来"这种能力不足,而是"旧包长什么样"在信息上就不可判——段里带的序号只能证明"发送方当时选了它",不能证明"这个包是现在发的还是很久以前发的"。所以接收方不去猜,而是把问题退还给唯一能回答它的一方。

4.2 第三步在回答的问题

按"谁提问、谁回答"重排一次,分工就清楚了:第一步,发起方说"我要连,我的初始序号是这个";第二步,接收方说"你的序号我收到了,同时报一下我的序号";第三步,发起方说"我确实刚发过那个 SYN"。

第三个包的价值不在于"多确认一次",而在于它是唯一能回答"这个 SYN 是新的还是旧的"那句话的位置。下面这句是笔者的转述、不是规范原话:那个 SYN 是发起方自己发的,只有它知道自己刚刚发过一个、序号是什么;所以"请发送方确认",是把一个不可判的问题变成可判的问题。

顺带澄清一个常见误读:三步握手常被讲成"确认对方在线",而规范给的首要原因不是这个,见下一节。

4.3 规范把"首要原因"写在了明处

§3.5 里有一句直接点题(表 A 第 14 行):

The principal reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion.

首要原因是防止"旧的重复连接发起"造成混淆。注意用词:不是"为了双方都确认一下",而是冲着旧包去的。"两端都还活着"更像是顺带得到的结果,而不是它被设计出来的理由——把主次换过来的人,往往会在"对方明明在线为什么还连不上"这类问题上绕圈。

顺带回答一个自然的追问:"那我平常会碰到旧包吗?"规范在讲"安静时间"时说得克制:although it is not felt to be necessary in most current implementations(表 A 第 15 行),并交代今天的实际使用中相关条件已足够不可能,it is safe to ignore——**机制为了边界情况而存在,不等于边界情况天天发生。**本文只写到机制这一层,不展开任何构造或触发方式。

本章可以带走的一句:两手往返不够,是因为接收第一个 SYN 的一侧没有办法当场判断这个段是不是旧的,只能把这个判断退还给唯一能回答它的发送方;而规范给握手的首要原因写得很清楚——防止旧的重复连接发起造成混淆。

五、同时打开:规范承认的正常路径,以及"看起来像"的那种

5.1 两边同时发起,规范说是允许的

第 3 章讲的是"一主动一被动"的常见走法。规范紧接着说明了另一种走法同样成立(表 A 第 16 行):

The procedure also works if two TCP peers simultaneously initiate the procedure. When simultaneous open occurs, each TCP peer receives a SYN segment that carries no acknowledgment after it has sent a SYN.

这里有个细节值得停一下:每一侧都是在"自己发出 SYN 之后"才收到一个不带确认的 SYN,所以两侧都会经过同一个中间状态。§3.5 对它的描述是(表 A 第 17 行):

Each TCP peer’s connection state cycles from CLOSED to SYN-SENT to SYN-RECEIVED to ESTABLISHED.

两条路都要走SYN-SENT与SYN-RECEIVED。而且这不是"也允许"这种软口气,规范用的是 MUST 级别(表 A 第 18 行):

A TCP implementation MUST support simultaneous open attempts (MUST-10).

“必须支持”——所以"同时打开"是一条正常路径,不是异常处理分支。这也修正了第 3 章留下的一句话:把SYN-RECEIVED理解成"对端那一侧的中间状态"通常够用,但并不准确,因为同时打开时发起方自己也会走到它。

5.2 但"看起来像同时打开",可能是一次旧重复 SYN

规范讲完正常路径后立刻补了一句提醒(表 A 第 19 行):

the arrival of an old duplicate SYN segment can potentially make it appear, to the recipient, that a simultaneous connection initiation is in progress

注意措辞是make it appear——“看起来像”。接收方看到的画面(自己也发过、又收到一个不带确认的 SYN)与真正的同时打开在画面上很像,但来路完全不同:一个是两边真的同时发起,一个是一个早该消失的旧包又冒了出来。规范随即说明了接收方的实际处境。§3.5 在描述"从旧重复 SYN 中恢复"的那张图时写道(表 A 第 20 行):

At line 3, an old duplicate SYN arrives at TCP Peer B. TCP Peer B cannot tell that this is an old duplicate, so it responds normally (line 4).

**B 分辨不出来,所以它照常回应。**这不是疏忽,而是第 4 章那条结论的必然结果:**单看一个包,无法判断它是不是旧的。**分辨的责任落在发起方那一侧——它发现回来的确认对不上,就回一个复位段;接收方收到后回到LISTEN,随后真正的 SYN 到了,握手照常走完。

规范对这套处置给了一句总结(表 A 第 21 行):Proper use of "reset" segments can disambiguate these cases.——正确使用复位段,可以把这几种情况区分开。

画面真实来路规范的态度
两侧都在等对方两边真的同时发起正常路径,实现必须支持
两侧都在等对方一个旧的重复 SYN 冒了出来接收方分辨不出,靠复位段区分

这两行画面几乎一样,处置方向却不同:**同一种现象不能默认它属于哪一类,得看规范给出的判别手段有没有被用上。**本文只写到"规范承认这套处置存在"这一层,不写任何构造这类情形的方法。

TCP 连接建立过程速查图:本文讲的状态走法与"同时打开 / 看起来像"的区分,都拆自这张图的骨架。它把十一个状态和建立阶段的关系画在一页上,放在资料包里,扫码即可获取:

本章可以带走的一句:同时打开是规范用MUST要求实现支持的正常路径,两侧都会走SYN-SENT与SYN-RECEIVED;而"看起来像同时打开"可能只是一个旧的重复 SYN——因为接收方分辨不出来,区分要靠复位段的正确使用。

六、把四个状态放回排障:现象、状态与"在等什么"

本章只做一件事:把LISTEN、SYN-SENT、SYN-RECEIVED、ESTABLISHED这四个状态,逐一对应到界面上那三种现象。不讲任何探测手段,也不回头去讲监听侧该取什么值。

6.1LISTEN:有东西在等,但等的不是"你"

回到第 3 章那句any remote TCP peer and port:LISTEN只说明有一个进程在这个位置等连接请求,不说明它会接受你的请求——它等的不是"你",而是"任意来客"。

那"连接被拒绝"是怎么来的?它来自对侧的 CLOSED。§3.5.2 写得很直接(表 A 第 22 行):

If the connection does not exist (CLOSED), then a reset is sent in response to any incoming segment except another reset. A SYN segment that does not match an existing connection is rejected by this means.

——**一个与任何已有连接都不匹配的 SYN,就是这样被拒绝的。**所以"被拒绝"的准确含义是:**对侧在那个四元组上没有对应的 TCB,于是回了一个复位段。**它回答的问题是"对侧此刻有没有在与这个请求对应的连接上等";至于为什么没有,可能的原因有好几条,属于监听侧那条轴,本文不展开。

又因为第 2 章那条结论——在那一侧看来"刚关掉"和"从来没建立过"长得一样——"被拒绝"本身不区分这两种情况,这是它最容易误读的地方。

6.2SYN-SENT:包出去了,回音没来

本侧停在SYN-SENT,意思是请求已经发出,还没等到一个匹配的请求回来,界面上的表现就是"卡住转圈"。要分清两件完全不同的事:没有回音,只能继续等到超时;收到了复位,会立刻结束等待,表现就是 6.1 里那个"瞬间被拒绝"。

也就是说,“慢"和"快"的差别在于回音是"没有"还是"是复位”。没有回音的原因之一,是通路上的某个环节把包丢掉了;通路本身怎么走、在哪一段出的问题,属于另一条轴,本文只解释状态。

⚠️代码待验证

# 只看本机上停在"等回音"这一段的 TCP 记录ss-tanstate syn-sent# macOS 上用 netstat 加过滤看同一类记录netstat-an-ptcp|grep-isyn_sent

6.3SYN-RECEIVED:中间那一小段窗口

对侧停在这个状态,表示它既收到过也发出过连接请求,正在等确认。它对应一小段时间:我方的 SYN 到了、对方回的确认也回来了、但第三步还没到。这段时间通常很短,第三步丢了或延迟就会被拉长。第 5 章还提醒过:同时打开时发起方自己也会走它,所以看到它并不必然意味着"我是应答方"。

6.4ESTABLISHED:只有到这里,数据才交得出去

ESTABLISHED的定义是an open connection, data received can be delivered to the user——**连接打开,收到的数据可以交付给用户。**规范还补了一句它的重要性(表 A 第 23 行):

so long as the receiving TCP endpoint doesn’t deliver the data to the user until it is clear the data is valid (e.g., the data is buffered at the receiver until the connection reaches the ESTABLISHED state, given that the three-way handshake reduces the possibility of false connections)

——在数据被确认为有效之前,接收端不把它交给用户(比如先缓存在接收侧,直到连接到达ESTABLISHED)。这一句正好解释了第 1 章那个"几个空包":那几个包不是浪费,它们就是把连接推到ESTABLISHED的过程。

界面上看到的现象本侧可能在的状态对侧可能在的状态在等什么
先几个空包,然后正常经过SYN-SENT→ESTABLISHED经过SYN-RECEIVED→ESTABLISHED三步依次走完
连接被拒绝(几乎不等)发出请求后收到复位该四元组上没有 TCB等不到"匹配",被复位结束
一直卡到超时停在SYN-SENT可能根本没收到等一个始终没来的回音

最后给三个只读的观察动作,用来把上面的状态在本地对上。它们都只查看本机已有的连接记录,不向任何外部目标发探测。

⚠️代码待验证

# 只看处于监听状态的 TCP 端点ss-tln# 只看已经建立的 TCP 连接ss-tanstate established# macOS 上没有 ss,用 netstat 加过滤看监听与已建立netstat-an-ptcp|grep-ilistennetstat-an-ptcp|grep-iestablished

⚠️代码待验证

# 用 lsof 按状态列出本机 TCP 连接,适合同时看"哪个进程在占"lsof-iTCP-sTCP:LISTENlsof-iTCP-sTCP:ESTABLISHED

本章可以带走的一句:四个状态各自对上一段时间——LISTEN是"有东西在等,但等的不是某个特定的人";SYN-SENT是"发出了没回音"(收到复位则立刻结束);SYN-RECEIVED是"第三步还没到"的短窗口;ESTABLISHED才是"数据可以交给用户"的那一步。

七、收束:一条主线与六项自查

7.1 一条主线

整篇可以收在一句话上:连接是两端各自的一份 TCB,建立过程就是让两份记录对得上。沿这条线:三种现象是同一段过程的三个位置(第 1 章);没有"管道",CLOSED甚至是虚构的(第 2 章);"三步"是四件事合并两条的结果(第 3 章);两步不够,是因为一侧没法判断这个段是不是旧的(第 4 章);同时打开是正常路径,"看起来像"另有来路(第 5 章)。

7.2 六项自查

下次再遇到"连不上",按顺序问自己六句:

  1. **我这一侧现在记的是什么状态?**先分清观察的是哪一端,别把两端的结论混着用。
  2. **对侧是"瞬断"还是"长等"?**瞬断通常意味着收到复位,长等通常意味着回音没来。
  3. **我看到的SYN-RECEIVED,真是应答方的那个吗?**它也可能出现在主动发起的一侧。
  4. **现象和状态对得上吗?**对不上时先怀疑"我看的那份记录不是这条连接的记录"。
  5. 把现象套回三个位置:停在LISTEN对侧没有记录、停在SYN-SENT等不到回音、还是停在SYN-RECEIVED差最后一步?
  6. **有没有更省事的规范层解释?**很多看起来矛盾的现象,答案就是某一侧本来就没有判断所需的全部信息。

7.3 一条纪律

最后一句:本文讲的全是建立过程本身。任何"造出半个连接""让某一侧停在中间状态"的操作都不属于本文范围,也不在这里提供思路;规范原文只用来说明机制为什么这么设计,不用来当作操作指引。

配套资料获取:这篇里反复用来"对上号"的那张状态速查图,和一套自建靶场环境的搭建对照表,都放在同一个资料包里。后面想按状态去读现象,先把图放在旁边对着看会快很多,扫码即可获取:

本章可以带走的一句:遇到"连不上",先回答"哪一侧、什么状态、在等什么"这三个问题;三个问题都能答上来时,现象基本已经自己说出答案了。

附表 A:本文引用事实与官方出处对照表

#事实(一句)出处核验日期本文位置
1建立连接所用的过程在规范里就叫 “three-way handshake”RFC 9293 §3.5(首句)2026-10-13第 1 章
2连接状态共十一个,最后一个是虚构态CLOSEDRFC 9293 §3.3.22026-10-13第 2 章
3CLOSED是虚构的,因为它代表"没有 TCB、因而没有连接"RFC 9293 §3.3.22026-10-13第 2 章
4连接要维护的变量被设想成放在一份叫 TCB 的连接记录里RFC 9293 §3.3.12026-10-13第 2 章
5TCB 里存的变量包括本地与远端的 IP 地址和端口号RFC 9293 §3.3.12026-10-13第 2 章
6LISTEN= 等任意远端 TCP 对端与端口的连接请求RFC 9293 §3.3.22026-10-13第 3、6 章
7SYN-SENT= 发出连接请求之后,等一个匹配的连接请求RFC 9293 §3.3.22026-10-13第 3、6 章
8SYN-RECEIVED= 既收到也发出连接请求之后,等确认RFC 9293 §3.3.22026-10-13第 3、6 章
9ESTABLISHED= 连接已打开,收到的数据可交付用户RFC 9293 §3.3.22026-10-13第 3、6 章
10同步要求每侧发出自己的初始序号并收到确认,同时收到对方的初始序号并给出确认RFC 9293 §3.4.12026-10-13第 3 章
11因为第 2、3 步可合并到一条消息,所以叫三消息握手(3WHS)RFC 9293 §3.4.12026-10-13第 3 章
12passive OPEN 表示进程想接受进来的连接请求(与 active OPEN 相对)RFC 9293 §3.3.22026-10-13第 3 章
13收到第一个 SYN 的一侧无法知道这个段是不是旧的,所以必须请发送方确认这个 SYNRFC 9293 §3.4.12026-10-13第 4 章
14三步握手的首要原因是防止旧的重复连接发起造成混淆RFC 9293 §3.52026-10-13第 4 章
15规范说"安静时间"在多数现行实现里并不必要,实际使用中相关条件已可安全忽略RFC 9293 §3.4.22026-10-13第 4 章
16两个对端同时发起时该过程同样能工作;同时打开时每侧在发出 SYN 后收到一个不带确认的 SYNRFC 9293 §3.52026-10-13第 5 章
17同时打开时每侧状态依次经过CLOSED→SYN-SENT→SYN-RECEIVED→ESTABLISHEDRFC 9293 §3.52026-10-13第 5 章
18实现必须支持同时打开尝试(MUST-10)RFC 9293 §3.52026-10-13第 5 章
19旧的重复 SYN 可能让接收方看起来像正在进行同时连接发起RFC 9293 §3.52026-10-13第 5 章
20接收方分辨不出旧重复,于是照常回应RFC 9293 §3.5(Figure 8 说明)2026-10-13第 5 章
21正确使用复位段可以把这些情况区分开RFC 9293 §3.52026-10-13第 5 章
22连接不存在(CLOSED)时对进来的段回复位;不匹配任何连接的 SYN 就是这样被拒绝的RFC 9293 §3.5.22026-10-13第 6 章
23数据被确认有效之前接收端不交给用户(例如缓存到连接到达ESTABLISHED)RFC 9293 §3.52026-10-13第 6 章

说明:本文全部规范原文取自 RFC 9293(2022-08,本批核验时为本机留存的原文文本),上表均为逐字口径。本文未在本机做过任何 TCP 抓包或状态观察,因此第 2、3、6 章的命令片段一律标注"代码待验证",不作为结论。

附表 B:术语速查表

术语一句话解释易混点
TCB保存一条连接各项变量的连接记录连接不是"管道",是两端各一份记录
CLOSED规范里的虚构状态,代表"没有 TCB"不是"关掉了",是"没有这份记录"
LISTEN在等任意远端的连接请求只说明有东西在等,不说明它会接受你
SYN-SENT请求已发出,在等一个匹配的请求回来收到复位会立刻结束,与"超时"是两回事
SYN-RECEIVED请求既收到也发出过,在等确认不专属于应答方,同时打开时发起方也经过它
ESTABLISHED连接已打开,数据可以交付用户只有到这里,数据才交得出去
初始序号(ISN)每一侧为自己选的起始序号与全局时钟无关,所以旧包无法靠它自证新旧
同时打开两端各自主动发起,规范用 MUST 要求支持是正常路径,不是故障
旧重复 SYN早该消失却又出现的连接请求接收方分辨不出,只能照常回应

写在最后:这篇用到的资料

写这篇文章时,我一直在回想自己第一次盯着抓包窗口发愣的样子——明明只看到几个"空包",网页却好好地打开了。把 RFC 9293 里那几段状态定义读完之后才明白:那几个包不是浪费,它们就是把连接推到能交付数据那一步的过程。顺手也整理了几份配套的东西:

  • 靶场环境对照表:DVWA、upload-labs 在 Windows / macOS / Linux 三平台的可行性与推荐路径
  • Web 安全学习路线图:从基础打牢到安全管理,四个阶段各学什么
  • 常用靶场清单:每个靶场练什么、适合哪个阶段

资料是我自己整理的,放在下面这个码上,扫码即可获取:

添加时备注「靶场」,优先通过。

拿到之后建议先看环境对照表那一份,再把自己靶场里"几个空包之后才出数据"的那次抓包对照着走一遍"哪一侧、什么状态、在等什么"这三个问题,下次再看到卡住转圈,就知道该往哪一段去想了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 8:51:27

二元Probit与Logit模型完全指南:从潜变量到边际效应

1. 为什么单独把二元Probit和Logit拎出来聊 做离散选择建模的人,绕不开二元选择模型。你手头有一组数据,因变量只有两个取值——用户买还是不买、客户违约还是不违约、病人确诊还是没确诊——这时候普通最小二乘法(OLS)就不太够用…

作者头像 李华
网站建设 2026/10/13 8:51:21

离心泵设计实战:从比转数到ANSYS验证的完整闭环

简介:本资源是华中科技大学出品的《离心泵设计教程》系统性学习资料,面向机械工程、能源动力及流体机械方向的本科生、研究生与工程技术人员,聚焦离心泵原理理解、结构设计与性能优化等核心能力培养,切实解决课程学习、课程设计及…

作者头像 李华
网站建设 2026/10/13 8:49:55

自建光伏电池模型的MPPT电压控制算法仿真与ESP32移植

做光伏MPPT仿真的时候,大多数人第一反应是打开Simulink里的PV Array模块,拖出来直接用。我之前也是这么干的,但折腾过几轮之后发现一个尴尬的事:算法跑出来效果不好,你分不清是MPPT策略本身的问题,还是模型…

作者头像 李华
网站建设 2026/10/13 8:49:52

Linux 上使用 yum 安装 Jenkins 的完整指南:从环境准备到彻底卸载

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 8:49:14

macOS下CLion配置OpenMP全链路指南

1. 为什么在 macOS 上用 CLion 跑 OpenMP 不是“点一下就运行”那么简单OpenMP 在 macOS 上的编译运行,从来就不是 Linux 或 Windows 环境下的“开箱即用”。我第一次在某高校实验室接手一个跨平台图像并行处理 Demo 时,原以为把 Linux 下跑通的 CMakeLi…

作者头像 李华
网站建设 2026/10/13 8:48:02

XGBoost官方文档精读指南:从参数原理到调参实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华