前言
很早以前,去面试,面试官问我,tcp 连接一共有多少种状态以及各状态的含义。我一脸懵逼,我知道一些状态,如 LISTEN、TIME_WAIT 等,但没有关注过总共有多少种状态,更别说每种状态的意义了,后面为了面试详细看了下 tcp 协议状态,虽然当时记住了(其实也只是粗略的知道),后面总是会忘记,又去搜索,现在将其记下
TCP 三次握手和四次挥手
tcp11 中状态及变迁其实基本包含在正常的三次握手和四次挥手中,除开 CLOSING
tcp 正常三次握手
从图片流程看,正常的三次握手从服务端打开监听监听(LISTEN)-> 客户端先发起 SYN 请求 -> 服务端发起 SYN 及 ACK 确认 -> 客户端再确认即三次握手 TCP 连接成功
而三次握手里面也包含 tcp 其中四种状态及变迁
LISTEN
服务端状态,应用程序打开监听端口,处理来自客户端 TCP 端口的连接请求
SYN_SENT
客户端状态,当客户端通过应用程序 connect()连接时,客户端 TCP 发送 SYN 请求主动建立连接,此时状态为 SYN_SENT
SYN_RECV
服务端状态,当收到客户端 SYN 请求后,服务端会发送一个 SYN 连接请求及 ACK 确认到客户端,再等待对方连接请求确认,这时状态为 SYN_RECV,如果发现有很多 SYN_RCVD 状态,可能受到了 SYN FLood 的 Dos 攻击
ESTABLISHED
当客户端回复正确的 ack 值后,就建立一个打开的连接,客户端和服务端就都进入 ESTABLISHED 状态,此时便可以 PSH 数据
tcp 正常四次挥手
从图片流程看,正常的四次握手包含 6 种 tcp 状态变迁
如主动发起关闭方为客户端
客户端发送 FIN 进入 FIN_WAIT1 -> 服务端发送 ACK 确认并进入 CLOSE_WAIT(被动关闭)状态 -> 客户端收到 ACK 确认后进入 FIN_WAIT2 状态 -> 服务端再发送 FIN 进入 LAST_ACK 状态 -> 客户端收到服务端的 FIN 后发送 ACK 确认进入 TIME_WAIT 状态 -> 服务端收到 ACK 确认后进入 CLOSED 状态断开连接 -> 客户端在等待 2MSL 的时间如果期间没有收到服务端的相关包请求,则进入 CLOSED 状态断开连接
FIN_WAIT1
客户端调用 close()关闭连接后,TCP 发出 FIN 请求主动关闭连接,然后进入 FIN_WAIT1 状态
等待远程 TCP 连接中断请求或者确认
CLOSE_WAIT
被动关闭状态,TCP 接收到 FIN 后,就发送 ack 回应客户端的 FIN 请求,然后就进入了 CLOSE_WAIT 状态
FIN_WAIT2
半关闭状态,主动关闭端 (也就是客户端调用 close() 后)接收到 ack 确认后,此时进入 FIN_WAIT2 状态,该状态下,客户端应用程序依然能接收数据
LAST_ACK
服务端发送确认中断后,也发送 FIN 关闭请求,然后进入 LAST_ACK 最后确认关闭状态
TIME_WAIT
在主动关闭端接收到 FIN 后,TCP 就发送 ACK,并进入 TIME-WAIT 状态,该状态持保持由内核参数 net.ipv4.tcp_keepalive_time 控制时间,默认为 2 小时,之后主动关闭方也进入 CLOSED 状态关闭连接
CLOSED
TCP 连接关闭,被动关闭端在接收到 ack 包后,进入 CLOSED 状态关闭 TCP 连接
CLOSING 状态
CLOSING 状态一般较少出现,这种是客户端和服务端同时发起了 FIN 主动请求关闭。如客户端发送 FIN 主动关闭,但是没有收到服务端发来的 ACK 确认,而是先收到了服务端发来的 FIN 请求关闭连接,所以必须是同时
在进入 CLOSING 状态后,只要收到了对方对自己发送的 FIN 的 ACK,收到 FIN 的 ACK 确认就进入 TIME_WAIT 状态,因此,如果 RTT(Round Trip Time TCP 包的往返延时)处在一个可接受的范围内,发出的 FIN 会很快被 ACK 从而进入到 TIME_WAIT 状态,CLOSING 状态持续的时间就特别短,因此很难看到这种状态