现在的位置: 首页 > 综合 > 正文

谈谈keepalive,长连接与短连接

2019年04月21日 ⁄ 综合 ⁄ 共 1975字 ⁄ 字号 评论关闭

短连接的意义:
1.节省资源,每一个TCP/UDP的链接都会消耗一定的系统资源, 链接如果一直不断开,最终会消耗掉所有的资源,所以必须释放掉。
2.另外释放掉能保护后端的资源,如果攻击者通过空链接,链接到服务器上,如果服务器没有做合适策略会因为链接数过多而无法提供服务。

长连接
1.TCP 层的三次握手不是请求,而是建立连接的过程,是没有数据传输的,请求是对应应用层而言的,比如说客户机发送一个http请求这样
2.链接建立之后,如果应用程序或者上层协议一直不发送数据,或者隔很长时间才发送一次数据,当链接很久没有数据报文传输时如何去确定对方还在线,到底是掉线了还是确实没有数据传输,链接还需不需要保持,这种情况在TCP协议设计中是需要考虑到的。TCP协议通过一种巧妙的方式去解决这个问题,当超过一段时间之后,TCP自动发送一个数据为空的报文给对方,如果对方回应了这个报文,说明对方还在线,链接可以继续保持,如果对方没有报文返回,并且重试了多次之后则认为链接丢失,没有必要保持链接。
3.具体来说就说一个连接在2小时内没有任何动作,服务器就向客户机发送一个探测报文,对于客户机:
    (1)正常运行,并从服务器可达,TCP响应正常,保活定时器复位(再次获得2小时)
    (2)客户机崩溃,关闭或者正在重启,TCP无响应,75秒后超时,服务器稍后发送9个探测报文(共计10个),间隔都为75秒。TCP都没有响应,认为客户机已经关闭连接
    (3)客户机崩溃并重启完成:服务器将收到一个探测响应,这个响应是一个复位,使得服务器终止这个连接。
    (4)客户机正常运行,但是服务器不可达,探测无响应,10次探测后无响应,关闭

问题
1.维护太多的长连接可能会导致客户机连接越来越多,server崩溃(所以linux中没有全局开启长连接的选项)
2.由于设置keepalive导致在系统短暂故障时良好的连接被释放
3.维护长连接会造成额外的流量开销,消费了不必要的带宽
4.保活设置可以设置在客户端用于在双方都需要探测对方是否消失的场合
5.上面三个问题都在提示我们无特素需要不要设置长连接

如何开启keepalive
1. Linux中没有全局去开启keepalive的选项,必须在应用中socket中单独开启
2. linux中有三个选项影响到keepalive的行为 sysctl -a 查看
    
    net.ipv4.tcp_keepalive_intvl = 75    //前一个探测报文和后一个探测报文之间的时间间隔
    net.ipv4.tcp_keepalive_probes = 9    //探测的次数 心跳包个数

    net.ipv4.tcp_keepalive_time = 7200 //单位秒,表示在这个时间之后没有数据时启动探测报文,默认时间为2小时

3. TCP socket 中有三个选项和内核对应,通过setsockopt对socket进行单独设置
    TCPKEEPCNT: 覆盖 tcpkeepaliveprobes
    TCPKEEPIDLE: 覆盖 tcpkeepalivetime
    TCPKEEPINTVL: 覆盖 tcpkeepalive_intvl

TCP 的keepalive 和 HTTP 的keepalive
http请求默认是使用持久连接,即服务器在响应后保持连接,后续的请求通过该连接继续传输,减少程序的开销
使用方法即增加首部行 Connection:keep-alive (开启)
                          Connection:close    (关闭)

代码实现
int s;
int keepAlive = 1;    
int keepIdle = 5;        //默认为7200即2小时
int keepInterval = 5;    //默认75秒
int keepCount = 3        //默认为9次

//使用长连接
if(setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(void*)&keepAlive,sizeof(keepAlive)) == -1)
{
    //if error
}

//设置选项
if(setsockopt(s,SOL_TCP,TCP_KEEPIDLE,(void *)&keepIdle,sizeof(keepIdle)) == -1)
{
    //if error
}

if(setsockopt(s,SOL_TCP,TCP_KEEPINTVL,(void *)&keepInterval,sizeof(keepInterval)) == -1)
{
    //if error
}

if(setsockopt(s,SOL_TCP,TCP_KEEPCNT,(void *)&keepCount,sizeof(keepCount)) == -1)
{
    //if error
}

抱歉!评论已关闭.