TCP状态转移总结

简单总结几个个人觉得较为重要的TCP状态。

20170120191710076.png

名词定义:

  • 客户端:发起connect操作的端
  • 服务端:发起bind操作的端
  • 主动关闭端:主动发起四次挥手端
  • 被动关闭端:被动接收四次挥手FIN报文端

CLOSED

  • 客户端发送SYN后进入SYN_SENT,若超时未收到ACK,则进入CLOSED
  • 被动关闭端接收到FIN后,发送ACK后进入CLOSE_WAIT,等待应用可进入CLOSED状态后,发送FIN后进入LAST_ACK状态,等待并接收到主动关闭端的ACK后进入CLOSED状态
  • 主动关闭端接收到FIN后,进入TIME_WAIT,等待2MSL时间后,进入CLOSED状态
  • 通过设置SO_LINGER可干预内核对于socket close动作的静默处理

CLOSE_WAIT

若程序有大量socket进入此状态,则意味着被动关闭端大量的连接在收到FIN后,程序没有主动将socket close掉。对应到Java的Mina或Netty框架,应该在IDLE或者EXCEPTION_CAUGHT时,主动将socket进行close。

FIN_WAIT

  • FIN_WAIT-1是主动关闭端发送FIN后进入的状态
  • 主动关闭端若收到被动关闭端ACK,则进入FIN_WAIT-2

image.png

服务端的SYN_RCVD与ESTABLISHED

  • 服务端处于SYN_RCVD的Socket存在于服务端的半连接队列中,队列数量配置内核参数tcp_max_syn_backlog。臭名昭著的SYN Flood攻击便是利用TCP服务端的SYN_RCVD状态进行攻击的(服务端静默重发ACK五次),半连接队列满了之后,静默处理是拒绝接受新的SYN,攻击者由此达到了拒绝服务攻击的目的,可通过Linux的SYNcookie防范此攻击(此时tcp_max_syn_backlog值无效)
  • 服务端处于ESTABLISHED的Socket存在于服务端的全连接队列,队列数量配置内核参数backlog,队列满了将拒绝接受accept新连接,可配置内核参数设置队列满之后静默丢弃客户端的ACK还是发送回一个RST

image.png

TIME_WAIT

如果C端不维持TIME_WAIT状态,而是FIN_WAIT2后直接进入CLOSED状态,那么C端将响应RST分节,S端收到后将此分节解释成一个错误,因此若想实现正常关闭,此环节必不可少;
MSL是一个IP数据报能在互联网上存在的最长时间,而TIME_WAIT持续的时间是两个MSL,这实际上是对路由器异常的容错,防止程序收到脏数据;