TCP的状态变迁及RST报文段产生与处理

TCP状态变迁

TCP的状态变迁及RST报文段产生与处理_第1张图片
CLOSE:                socket的初始状态,没有进行任何操作(connect, listen)之前的状态
LISTEN:               可以接受SYN的状态,服务器等待连接
SYN_RECEIVED:    一个连接请求已经到达,等待确认
SYN_SENT:            发出连接请求,等待确认
ESTABLISED:      连接建立成功,可以进行数据通信 
CLOSE_WAIT:       对方已关闭连接,等待本地用户关闭
FIN_WAIT_1:         应用程序关闭连接
FIN_WAIT_2:         对方已经知道本端不会再发送数据
CLOSING:              对待对方的连接终止请求确认
TIME_WAIT:          双方都尝试关闭连接,等待一段时间,以防止ACK丢失
LAST_ACK:         等待对方确认关闭连接

同步状态:ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, CLOSE_WAIT, CLOSING, LAST_ACK, TIME_WAIT
非同步状态:LISTEN,SYN_RECEIVED, SYN_SENT

从LISTEN到SYN_SENT的变迁是正确的,但伯克利的TCP软件并不支持它。这里也没有画出。

从程序开发者的角度来看RST的产生和RST的处理

RST的产生

  1. 向不存在的端口发起连接
  2. 一些延迟的包导致连接无法正常建立,例如一个旧的SYN副本
  3. 程序异常终止(依赖于系统,有的会发送FIN, 有的发送RST)
  4. 设置了SO_LINGER选项支持异常关闭,并调用close
  5. 已关闭的端口(调用close)收到数据

RST的处理

内核对rst的处理由下面这个函数完成
/* When we get a reset we do this. */
void  tcp_reset  ( struct  sock  * sk  )
{
        /* We want the right error as BSD sees it (and indeed as we do). */
        switch  ( sk  ->sk_state) {
        case  TCP_SYN_SENT:
              sk ->sk_err =  ECONNREFUSED  ;
              break ;
        case  TCP_CLOSE_WAIT:
              sk ->sk_err =  EPIPE  ;
              break ;
        case  TCP_CLOSE:
              return ;
        default :
              sk ->sk_err =  ECONNRESET  ;
      }
        /* This barrier is coupled with smp_rmb() in tcp_poll() */
      smp_wmb();

        if  (!sock_flag( sk  , SOCK_DEAD))
              sk ->sk_error_report( sk  );

      tcp_done(  sk );
}
对rst的处理结果最终要反应给上层应用。通过设置errno告诉上层TCP的当前状态。对于与tcp_reset函数
我们可以得到如下的处理流程图
TCP的状态变迁及RST报文段产生与处理_第2张图片
即,
  1. 如果在建立连接的过程中收到RST,上层得到的错误就是ECONNREFUSED,一般就是connect返回失败,errno
    的值被设置为ECONNREFUSED。
  2. 如果对方已经关闭连接(调用了close, 本端处于CLOSE_WAIT状态),继续调用send发送数据,就会收到RST,这种情况
    下设置错误号为EPIPE。
  3. 其它情况下,收到RST,都设置错误号为ECONNRESET
掉用close函数的TCP会进入CLOSE状态,调用shutdown可能进入FIN_WAIT_2状态。

你可能感兴趣的:(TCP的状态变迁及RST报文段产生与处理)