TCP之keepalive机制的应用场景

若是TCP链接被对方正常关闭,也就是说,对方是正确地调用了close或者shutdown的话,那么Recv或Send调用就能立刻返回,而且报错。这是因为close或者shutdown有个正常的关闭过程,会告诉对方“TCP链接已经关闭,你不须要再发送或者接受消息了”。编程

可是,若是链接被意外断开,客户端并无正常关闭socket。双方并未按照协议上的四次挥手去断开链接。那么这时候正在执行Recv或Send操做的一方就会由于没有任何链接中断的通知而一直等待下去,也就是会被长时间卡住。像这种若是一方已经关闭或异常终止链接,而另外一方殊不知道,咱们将这样的TCP链接称为半打开的。服务器

 

解决意外中断办法都是利用保活机制。而保活机制分又可让底层实现也可本身实现。网络

一种是应用层的心跳机制;socket

还有一种就是启用TCP的keepAlive机制;tcp

 

以服务器端为例,若是当前server端检测到超过必定时间没有数据传输,那么会向client端发送一个keep-alive packet(该keep-alive packet就是ACK和当前TCP序列号减一的组合),此时client端应该为如下三种状况之一:server

1. client端仍然存在,网络链接情况良好。此时client端会返回一个ACK。server端接收到ACK后重置计时器(复位存活定时器),在必定时间后再发送探测。若是链接上一直有数据传输,那么在该时间基础上向后推延一段时间。基础

2. 客户端异常关闭,或是网络断开。在这两种状况下,client端都不会响应。服务器没有收到对其发出探测的响应,而且在必定时间(系统默认为1000 ms)后重复发送keep-alive packet,而且重复发送必定次数。cli

3. 客户端曾经崩溃,但已经重启。这种状况下,服务器将会收到对其存活探测的响应,但该响应是一个复位(RST),从而引发服务器对链接的终止。服务器端

 

在应用层socket编程的表现为:当tcp检测到对端socket再也不可用时(不能发出探测包,或探测包没有收到ACK的响应包),select/epoll会返回socket可读,而且在recv时返回-1,同时置上errno为ETIMEDOUT。select

 

范例:

  1.  int keepAlive = 1; // 开启keepalive属性  
  2.  int keepIdle = 60; // 如该链接在60秒内没有任何数据往来,则进行探测   
  3.  int keepInterval = 5; // 探测时发包的时间间隔为5 秒  
  4.  int keepCount = 3; // 探测尝试的次数.若是第1次探测包就收到响应了,则后2次的再也不发.  
  5.   
  6.  setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));  
  7.  setsockopt(rs, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));  
  8.  setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));  
  9.  setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));   
相关文章
相关标签/搜索