TCP 协议,全称为"传输控制协议"。
1. TCP 协议段格式
给出几个定义 :
-
16位源端口号
:用于标识发送端的应用程序。 -
16位目的端口号
:用于标识接收端的目标应用程序。 -
32位序号
:用于标识发送的每一个字节流中的第一个字节位置;确保接收端能够按照正确的顺序重组数据,即使数据包在传输中乱序到达。 -
32位确认序号
:用于告知发送端,"我已经成功接收 这个序号之前的所有数据 ,现在请从这个序号开始给我发新的数据" 。 -
4位首部长度
:指示 TCP 头部的长度,以 4字节 为单位;首部长度
的范围是 5~15,标识 TCP 头部的长度为 20~60 字节。 -
标志位
:用于控制 TCP 连接的状态。SYN
、ACK
、FIN
、RST
、PSH
、URG
2. 三次握手
2.1 传统的三次握手过程
三次握手过程,确保了两个主机都可以互相发送和接收数据。
服务端状态变化:
CLOSED ---> LISTEN
:服务端调用 listen() 后进入 LISTEN 状态,等待客户端连接。LISTEN ---> SYN_RCVD
:监听到连接请求(即收到 SYN 包),将该连接放入内核等待队列,并向客户端发送 SYN-ACK 包。SYN_RCVD ---> ESTABLISHED
:服务端收到客户端的 ACK 包后进入 ESTABLISHED 状态,可以读写数据。
客户端状态变化:
CLOSED ---> SYN_SENT
:客户端调用 connect(),发送 SYN 报文。SYN_SENT ---> ESTABLISHED
:调用 connect() 成功,收到来自服务器的 SYN-ACK 包后,进入 ESTABLISHED 状态。
2.2 三次握手过程触发 RST
在 TCP 三次握手过程中,被请求建立连接的那一端尚未完成握手(未收到最终的 ACK 包),就意外收到了数据包,则触发 RST(连接重置) 。
RST 包的作用:
- 立即中断连接,告知对方当前连接不可用。
- 释放相关资源,避免内存泄露。
客户端收到 RST 包后,需要重新进行三次握手,建立连接。
3. 四次挥手
3.1 四次挥手过程
客户端状态变化:
ESTABLISTED ---> FIN_WAIT_1
:客户端调用 close() ,向服务端发送 FIN 报文,并进入 FIN_WAIT_1 状态。
通知服务器,客户端没有数据要发送了,但仍然可以接收数据。
-
FIN_WAIT_1 ---> FIN_WAIT_2
:客户端收到来自服务器的 ACK 报文,进入 FIN_WAIT_2 状态。 -
FIN_WAIT_2 ---> TIME_WAIT
:客户端收到来自服务器的 FIN 报文,进入 TIME_WAIT 状态,发出最后一个 ACK 包。
服务器状态变化:
-
ESTABLISHED ---> CLOSE_WAIT
:客户端主动关闭连接,服务器收到 FIN 报文后回应 ACK ,并进入 CLOSE_WAIT 状态。 -
CLOSE_WAIT ---> LAST_ACK
:进入 CLOSE_WAIT 状态后,服务器准备关闭连接,处理所有剩余数据;服务器真正调用 close() 关闭连接,向客户端发送 FIN 报文并进入 LAST_ACK 状态,等待最后一个 ACK(确认)。
-
LAST_ACK ---> CLOSED
:服务器收到了客户端对 FIN 的 ACK,关闭连接。
3.2 CLOSE_WAIT 状态
创建一个简易的 TCP 服务器和 TCP 客户端,并建立连接。
直接关闭客户端。
此时服务端进入 CLOSE_WAIT 状态,四次挥手没有完成。
如果服务器上大量出现 CLOSE_WAIT 状态,意味着服务器没有正确地关闭 socket ,导致四次挥手没有正常完成。
需要加上对应的 close ,解决此问题。
3.3 TIME_WAIT 状态
与 3.2
相同,创建一个简易的 TCP 服务器和客户端,并建立连接。
直接关闭服务器,再重新运行。
服务器进入 TIME_WAIT 状态。
TCP 协议规定,主动关闭连接的一方要处于 TIME_WAIT 状态,等待两个 MSL(maximum segment lifetime)的时间后,才能回到 CLOSED 状态。
-
MSL 是 TCP 报文的最大生存时间。
-
保证在传输方向上的尚未被接收、或迟到的报文段都已消失;否则服务器立即重启,会收到来自上个进程的迟到数据。
-
保证最后一个 ACK 报文可靠到达;如果最后一个 ACK 丢失,服务器会重发一个 FIN 数据报(客户端进程虽然不在,但 TCP 连接还在,可以重发 ACK)。