5.3 传输连接的建立与释放
本小节的服务端指资源提供方(对应 RFC 文档中的 “Application”),客户端指资源获取方(对应 RFC 文档中的 “User”)。
5.3.1 TCP 连接的建立
TCP 建立连接主要有以下步骤:
步骤 | 客户端状态 | 客户端 | 服务端 | 服务端状态 |
---|---|---|---|---|
CLOSED | LISTEN | |||
第 1 次握手 | SYN-SENT | (发起连接请求,随机生成一个 seq) SYN=1, seq=x | LISTEN | |
SYN-SENT | (收到客户端连接请求) | LISTEN | ||
第 2 次握手 | SYN-SENT | (响应针对 seq=x 的连接请求,随机生成另一个 seq) SYN=1, ACK=1, seq=y, ack=x+1 | SYN-RCVD | |
ESTABLISHED | (收到服务端 ACK) | SYN-RCVD | ||
第 3 次握手 | ESTABLISHED | (回复服务器对连接请求响应的确认) ACK=1, seq=x+1, ack=y+1 | SYN-RCVD | |
ESTABLISHED | (收到客户端对连接请求响应的确认) | ESTABLISHED |
可以看到:
- 前两次握手客户端和服务端使用的 seq 都是随机生成的。
- 客户端在第二次握手后就已经进入连接已建立状态了,因此:客户端在第三次握手时就可以携带数据了。
- 连接建立之后发送数据时使用的 seq 取决于计算机当前序列号计数器,而非建立连接时随机生成的 seq。
5.3.2 TCP 连接的释放
TCP 释放连接主要有以下步骤,表格中“客户端”表示主动要求释放连接的一方,“响应方”表示被释放连接的一方:
步骤 | 发起方状态 | 发起方 | 响应方 | 响应方状态 |
---|---|---|---|---|
ESTABLISHED | ESTABLISHED | |||
第 1 次挥手 | FIN-WAIT-1 | (发送释放连接请求,seq 取决于客户端当前序列号计数器) FIN=1, seq=u | ESTABLISHED | |
FIN-WAIT-1 | (收到客户端请求释放连接) | CLOSE-WAIT | ||
第 2 次挥手 | FIN-WAIT-1 | (响应客户端的连接释放请求,seq 取决于服务端当前序列号计数器) ACK=1, seq=v, ack=u+1 | CLOSE-WAIT | |
FIN-WAIT-2 | (收到服务端对连接释放请求的响应) | CLOSE-WAIT | ||
第 3 次挥手 | FIN-WAIT-2 | (发送连接释放请求,seq 取决于服务端当前序列号计数器) FIN=1, ACK=1, seq=w, ack=u+1 | LAST-ACK | |
TIME-WAIT | (收到服务端请求释放连接) | LAST-ACK | ||
第 4 次挥手 | TIME-WAIT | (响应服务端连接释放) ACK=1, seq=u+1, awc=w+1 | LAST-ACK | |
TIME-WAIT | (收到客户端对连接释放请求的响应) | CLOSED | ||
TIME-WAIT | (客户端等待两个 MSL) | CLOSED | ||
CLOSED | CLOSED |
可以看到:
- 既可以由客户端发起请求连接释放流程,也可以由服务端发起连接释放流程(即发起整个四次挥手的流程)。
- 四次挥手的本质其实是由连接释放发起方和响应方先后请求释放连接(即前两次挥手和后两次挥手)。
- 收到对方的连接释放请求,仅代表对方没有更多数据需要发送,因此当收到对方连接释放请求后,即使我方进入了 CLOSE-WAIT 状态,仍可以继续发送数据,这也是使用四次挥手而不是三次的原因。
- 四次挥手所使用的 seq 都取决于当前序列号计数器,那么此处存在第三方伪造连接释放请求,即 TCP 劫持的风险。
- (RFC-9293 3.6.1)TIME-WAIT 状态可以接收新的连接的握手以直接建立新的连接。
相关问题:
-
TIME-WAIT 的意义
当连接释放发起方进入 TIME-WAIT 状态时,之前发送的分段最多保持一个 MSL,在其到达连接释放接收方后,接收方发送的回复最多保持一个 MSL,因此一共需要两个 MSL 才能确保双方在连接释放前发送的所有报文完全从网络中消失,以避免新的连接受此影响。
-
客户端异常掉线的处理方式
当连接建立之后,客户端因为意外崩溃、断网等原因无法发送数据、释放连接,TCP 协议未定义此时如何处理。实践中不同操作系统有不同的处理方式,例如其中一种:
当连接建立后客户端长时间未发送数据,服务端则主动请求释放连接,并进入 FIN-WAIT-1 状态,若客户端响应释放连接,则连接正确释放;若客户端仍处于异常状态无法响应释放连接,于是服务端持续保持 FIN-WAIT-1 状态,并超时重传第一次挥手,直到到达服务器中定义的 TCP 超时时间,则直接释放连接。
5.8.3 TCP 连接的重置
当发生各种错误情况时,TCP 协议会生成重置事件,但客户端和服务端可随时对连接发起重置。作为一般规则,重置会在明显不适合当前连接到数据段到达时发送。
发起重置的一方应进入 TIME-WAIT 状态,即等待两个 MSL。
(RFC-9293 3.5.2)如果不清楚是否属于以下几种情况,则不得发送 RST:
-
若连接不存在,即尚未与对方建立连接,或与对方的连接已关闭,此时若收到除建立连接第一次握手的所 有报文,应回复 RST。例如:
若服务端尚未与客户端建立连接,但服务端收到了客户端的第二次握手的报文,则应回复 RST。
-
若连接已完整建立,即双方已准备好发送和接收数据,此时若客户端确认了服务端尚未发送的分段,应回复 RST。例如:
服务端收到客户端对序号为 1005 的分段的确认,而服务器仅发送到 1002,即尚未发送 1005 分段,则应回复 RST。
-
若连接已完整建立,此时若客户端收到了服务端发送的接收窗口以外的分段,不应回复 RST,而是回复服务端一个 ACK 告知客户端当前已确认的序号以及期望接收到的下一个序号。例如:
客户端已确认 1001 分段,下一个期望接收到的序号为 1002 ~ 1004,即接收窗口大小为 3,但服务端发送了 1005 分段,此时客户端应丢弃并回复 ACK,其中
seq=1001, ack=1002
。
因此:
- 当发起重置第一方进入 TIME-WAIT 状态时,可以接受对方发起的新的 SYN 报文,即第一次握手,此时可以立即开始连接建立流程。