1. TCP 三次握手(Three-Way Handshake)
三次握手用于建立 TCP 连接,确保客户端和服务器双方都准备好进行通信。
步骤:
-
第一次握手(SYN):
-
客户端向服务器发送一个
SYN
(Synchronize)包,表示请求建立连接。 -
包中包含客户端的初始序列号(
seq = x
)。 -
客户端进入
SYN_SENT
状态。
-
-
第二次握手(SYN + ACK):
-
服务器收到
SYN
包后,向客户端发送一个SYN + ACK
包,表示同意建立连接。 -
包中包含服务器的初始序列号(
seq = y
)和对客户端SYN
的确认号(ack = x + 1
)。 -
服务器进入
SYN_RECEIVED
状态。
-
-
第三次握手(ACK):
-
客户端收到
SYN + ACK
包后,向服务器发送一个ACK
(Acknowledgment)包,表示确认连接已建立。 -
包中包含对服务器
SYN
的确认号(ack = y + 1
)。 -
客户端和服务器都进入
ESTABLISHED
状态,连接建立完成。
-
图示:
客户端 服务器| || SYN (seq=x) || -------------------------------> || || SYN + ACK (seq=y, ack=x+1) || <------------------------------- || || ACK (ack=y+1) || -------------------------------> || |
为什么需要三次握手?
-
确保双方都能收发数据:通过三次握手,客户端和服务器都能确认对方的发送和接收能力。
-
防止旧的重复连接请求:如果客户端发送的
SYN
包是延迟的旧包,服务器可以通过客户端的ACK
包判断是否为有效连接。
2. TCP 四次挥手(Four-Way Handshake)
四次挥手用于关闭 TCP 连接,确保双方都完成数据传输并安全关闭连接。
步骤:
-
第一次挥手(FIN):
-
客户端(或服务器)发送一个
FIN
(Finish)包,表示请求关闭连接。 -
包中包含序列号(
seq = u
)。 -
发送方进入
FIN_WAIT_1
状态。
-
-
第二次挥手(ACK):
-
接收方收到
FIN
包后,发送一个ACK
包,表示确认收到关闭请求。 -
包中包含确认号(
ack = u + 1
)。 -
接收方进入
CLOSE_WAIT
状态,发送方进入FIN_WAIT_2
状态。
-
-
第三次挥手(FIN):
-
接收方完成数据处理后,发送一个
FIN
包,表示同意关闭连接。 -
包中包含序列号(
seq = w
)。 -
接收方进入
LAST_ACK
状态。
-
-
第四次挥手(ACK):
-
发送方收到
FIN
包后,发送一个ACK
包,表示确认关闭连接。 -
包中包含确认号(
ack = w + 1
)。 -
发送方进入
TIME_WAIT
状态,等待一段时间后关闭连接。 -
接收方收到
ACK
包后,关闭连接。
-
图示:
客户端 服务器| || FIN (seq=u) || -------------------------------> || || ACK (ack=u+1) || <------------------------------- || || FIN (seq=w) || <------------------------------- || || ACK (ack=w+1) || -------------------------------> || |
为什么需要四次挥手?
-
双向关闭:TCP 连接是全双工的,双方需要分别关闭自己的发送通道。
-
确保数据完整性:接收方需要时间处理未完成的数据,并在确认完成后发送
FIN
包。
3. TCP 状态转换
三次握手状态:
-
SYN_SENT
:客户端发送SYN
包后进入该状态。 -
SYN_RECEIVED
:服务器收到SYN
包并发送SYN + ACK
包后进入该状态。 -
ESTABLISHED
:连接建立完成,双方进入该状态。
四次挥手状态:
-
FIN_WAIT_1
:发送FIN
包后进入该状态。 -
FIN_WAIT_2
:收到对方的ACK
包后进入该状态。 -
CLOSE_WAIT
:收到对方的FIN
包后进入该状态。 -
LAST_ACK
:发送FIN
包后进入该状态。 -
TIME_WAIT
:发送最后的ACK
包后进入该状态,等待 2MSL(Maximum Segment Lifetime)后关闭连接。
4. 常见问题
为什么 TIME_WAIT
状态需要等待 2MSL?
-
确保最后的
ACK
包到达:如果最后的ACK
包丢失,对方会重传FIN
包,TIME_WAIT
状态可以重新发送ACK
包。 -
防止旧连接的重复数据包:等待 2MSL 可以确保网络中所有旧连接的包都消失,避免与新连接混淆。
如果服务器大量处于 CLOSE_WAIT
状态怎么办?
-
检查应用程序:可能是应用程序未正确关闭连接,导致
CLOSE_WAIT
状态堆积。 -
调整超时时间:可以通过调整
net.netfilter.nf_conntrack_tcp_timeout_close_wait
参数优化。
总结
-
三次握手:用于建立 TCP 连接,确保双方都能收发数据。
-
四次挥手:用于关闭 TCP 连接,确保双方都完成数据传输并安全关闭。
-
状态转换:TCP 连接在不同状态下转换,确保连接的可靠性和完整性。