`

socket参数详解:KeepAlive

阅读更多
TCP协议中有长连接和短连接之分。短连接在数据包发送完成后就会自己断开,长连接在发包完毕后,会在一定的时间内保持连接,即我们通常所说的Keepalive(存活定时器)功能。
默认的Keepalive超时需要7,200,000 milliseconds,即2小时,探测次数为5次。它的功效和用户自己实现的心跳机制是一样的。开启Keepalive功能需要消耗额外的宽带和流量,尽管这微不足道,但在按流量计费的环境下增加了费用,另一方面,Keepalive设置不合理时可能会因为短暂的网络波动而断开健康的TCP连接。

keepalive并不是TCP规范的一部分。在Host Requirements RFC罗列有不使用它的三个理由:(1)在短暂的故障期间,它们可能引起一个良好连接(good connection)被释放(dropped),(2)它们消费了不必要的宽带,(3)在以数据包计费的互联网上它们(额外)花费金钱。然而,在许多的实现中提供了存活定时器。
一些服务器应用程序可能代表客户端占用资源,它们需要知道客户端主机是否崩溃。存活定时器可以为这些应用程序提供探测服务。Telnet服务器和Rlogin服务器的许多版本都默认提供存活选项。
个人计算机用户使用TCP/IP协议通过Telnet登录一台主机,这是能够说明需要使用存活定时器的一个常用例子。如果某个用户在使用结束时只是关掉了电源,而没有注销(log off),那么他就留下了一个半打开(half-open)的连接。如果客户端消失,留给了服务器端半打开的连接,并且服务器又在等待客户端的数据,那么等待将永远持续下去。存活特征的目的就是在服务器端检测这种半打开连接。
也可以在客户端设置存活器选项,且没有不允许这样做的理由,但通常设置在服务器。如果连接两端都需要探测对方是否消失,那么就可以在两端同时设置(比如NFS)。


keepalive工作原理:
若在一个给定连接上,两小时之内无任何活动,服务器便向客户端发送一个探测段。(我们将在下面的例子中看到探测段的样子。)客户端主机必须是下列四种状态之一:
1) 客户端主机依旧活跃(up)运行,并且从服务器可到达。从客户端TCP的正常响应,服务器知道对方仍然活跃。服务器的TCP为接下来的两小时复位存活定时器,如果在这两个小时到期之前,连接上发生应用程序的通信,则定时器重新为往下的两小时复位,并且接着交换数据。
2) 客户端已经崩溃,或者已经关闭(down),或者正在重启过程中。在这两种情况下,它的TCP都不会响应。服务器没有收到对其发出探测的响应,并且在75秒之后超时。服务器将总共发送10个这样的探测,每个探测75秒。如果没有收到一个响应,它就认为客户端主机已经关闭并终止连接。
3) 客户端曾经崩溃,但已经重启。这种情况下,服务器将会收到对其存活探测的响应,但该响应是一个复位,从而引起服务器对连接的终止。
4) 客户端主机活跃运行,但从服务器不可到达。这与状态2类似,因为TCP无法区别它们两个。它所能表明的仅是未收到对其探测的回复。

服务器不必担心客户端主机被关闭然后重启的情况(这里指的是操作员执行的正常关闭,而不是主机的崩溃)。当系统被操作员关闭时,所有的应用程序进程(也就是客户端进程)都将被终止,客户端TCP会在连接上发送一个FIN。收到这个FIN后,服务器TCP向服务器进程报告一个文件结束,以允许服务器检测这种状态。
在第一种状态下,服务器应用程序不知道存活探测是否发生。凡事都是由TCP层处理的,存活探测对应用程序透明,直到后面2,3,4三种状态发生。在这三种状态下,通过服务器的TCP,返回给服务器应用程序错误信息。(通常服务器向网络发出一个读请求,等待客户端的数据。如果存活特征返回一个错误信息,则将该信息作为读操作的返回值返回给服务器。)在状态2,错误信息类似于“连接超时”。状态3则为“连接被对方复位”。第四种状态看起来像连接超时,或者根据是否收到与该连接相关的ICMP错误信息,而可能返回其它的错误信息。

linux内核包含对keepalive的支持。其中使用了三个参数:tcp_keepalive_time(开启keepalive的闲置时 长)tcp_keepalive_intvl(keepalive探测包的发送间隔)和tcp_keepalive_probes(如果对方不予应答,探测包的发送次数);在liunx中,keepalive是一个开关选项,可以通过函数来使能。具体地说,可以使用以下代码:
setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
当tcp检测到对端socket不再可用时(不能发出探测包,或探测包没有收到ACK的响应包),select会返回socket可读,并且在recv时返回-1,同时置上errno为ETIMEDOUT。此时TCP的状态是断开的。


keepalive参数设置代码如下:
// 开启KeepAlive
BOOL bKeepAlive = TRUE;
int nRet = ::setsockopt(socket_handle, SOL_SOCKET, SO_KEEPALIVE, (char*)&bKeepAlive, sizeof(bKeepAlive));
if (nRet == SOCKET_ERROR)
{
return FALSE;
}

// 设置KeepAlive参数
tcp_keepalive alive_in                = {0};
tcp_keepalive alive_out                = {0};
alive_in.keepalivetime                = 5000;                // 开始首次KeepAlive探测前的TCP空闭时间
alive_in.keepaliveinterval        = 1000;                // 两次KeepAlive探测间的时间间隔
alive_in.onoff                                = TRUE;
unsigned long ulBytesReturn = 0;
nRet = WSAIoctl(socket_handle, SIO_KEEPALIVE_VALS, &alive_in, sizeof(alive_in),
&alive_out, sizeof(alive_out), &ulBytesReturn, NULL, NULL);
if (nRet == SOCKET_ERROR)
{
return FALSE;
}

开启Keepalive选项之后,对于使用IOCP模型的服务器端程序来说,一旦检测到连接断开,GetQueuedCompletionStatus函数将立即返回FALSE,使得服务器端能及时清除该连接、释放该连接相关的资源。对于使用select模型的客户端来说,连接断开被探测到时,以recv目的阻塞在socket上的select方法将立即返回SOCKET_ERROR,从而得知连接已失效,客户端程序便有机会及时执行清除工作、提醒用户或重新连接。

TCP连接非正常断开的检测(KeepAlive探测)
此处的”非正常断开”指TCP连接不是以优雅的方式断开,如网线故障等物理链路的原因,还有突然主机断电等原因
有两种方法可以检测:1.TCP连接双方定时发握手消息 2.利用TCP协议栈中的KeepAlive探测
第二种方法简单可靠,只需对TCP连接两个Socket设定KeepAlive探测。


在windows下使用,要包含MSTcpIP.h的头文件。点击下面的链接即可下载这个文件
  MSTcpIP

备注:长连接虽好,但是比较好用但是占用系统资源比较大。个人建议如无特殊需要,用自己的心跳包机制最好
分享到:
评论

相关推荐

    setsockopt参数详解

    * SO_KEEPALIVE:保持连接。 * SO_LINGER:延迟关闭连接。 * SO_OOBINLINE:带外数据放入正常数据流。 * SO_RCVBUF:接收缓冲区大小。 * SO_SNDBUF:发送缓冲区大小。 * SO_RCVLOWAT:接收缓冲区下限。 * SO_...

    cSharp-socket-class.zip_C# socket类_C# socket详解_C# socket 编程_c#

    6. **套接字选项和属性**:Socket类有许多属性和方法用于设置和查询套接字选项,例如NoDelay(TCP_NODELAY)可以禁用Nagle算法以减少延迟,KeepAlive则可以开启心跳检测。 7. **关闭和释放资源**:完成通信后,记得...

    Linux Socket Programming By Example(pdf)

    ### Linux Socket编程示例知识点详解 #### 一、引言 《Linux Socket编程示例》是一本详尽介绍如何在Linux环境下使用Socket进行网络通信的书籍。本书由Warren W. Gay编写,由Que出版社出版于2000年。本书不仅提供了...

    利用Keep-Alive处理Socket网络异常断开的方法

    接下来,我们将展示一段C++代码示例,该示例演示了如何在Windows环境下设置TCP Keep-Alive参数以检测网络连接的异常断开。 ```cpp #include #include #include // 定义TCP Keep-Alive结构体 typedef struct tcp...

    TCP socket通信实例(心跳)

    ### TCP Socket通信实例:心跳机制详解 #### 一、引言 在计算机网络通信中,TCP(Transmission Control Protocol)作为一种面向连接的协议,为数据传输提供了可靠的保障。然而,在实际应用中,网络环境可能会出现...

    SocketDemo

    2. **保持连接**:通过设置Socket选项如SO_KEEPALIVE等,保持连接不被操作系统断开。 3. **心跳包机制**:定时发送心跳包检测连接状态,确保连接有效性。 #### 三、通信过程详解 在SocketDemo项目中,客户端与...

    socket-2.zip

    2. **API详解**:详述Socket编程涉及的函数,如connect(), bind(), listen(), accept(), send(), recv()等的使用方法和参数解析。 3. **实例演示**:提供客户端和服务端的代码示例,展示如何创建Socket,建立连接,...

    socket选项说明

    ### Socket选项详解 #### 引言 在深入探讨Socket选项之前,我们先回顾一下Socket的基本概念。Socket,或称为套接字,是网络通信中的一种重要机制,它为应用程序提供了在不同主机之间发送和接收数据的能力。在前几...

    redis3.0的配置指令详解.docx

    ### Redis 3.0 配置指令详解 Redis 3.0 版本作为一款高性能的键值存储系统,在配置方面提供了丰富的选项来满足不同场景的需求。本文将深入解析 `redis.conf` 文件中的各项配置指令及其意义,并给出推荐的配置值。 ...

    详解Nginx中HTTP的keepalive相关配置

    http keepalive 在http早期 ,每个http请求都要求打开一个tpc socket连接,并且使用一次之后就断开这个tcp连接。使用keep-alive可以改善这种状态,即在一次TCP连接中可以持续发送多份数据而不会 断开连接。通过使用...

    redis配置详解.docx

    7. **unixsocket** 和 **unixsocketperm**: 如果使用 Unix 套接字进行本地连接,可以配置这些选项。`unixsocketperm` 设置文件的权限。 8. **timeout**: 客户端无活动多久后 Redis 会断开连接。设置为 0 表示...

    apache+Tomcat负载平衡设置详解

    - `socket_keepalive`:设置为 `true` 以保持空闲连接的活跃状态。 四、负载平衡策略 Apache 提供多种负载平衡策略,如轮询(round-robin)、最少连接数(least connections)、IP 会话亲和(IP-based session ...

    MySocket.rar

    二、Socket类详解 Socket是网络通信的基础,它代表了网络上的一个通信端点,可以理解为一个数据传输的通道。C#中的System.Net.Sockets命名空间提供了Socket类,它支持TCP和UDP两种主要的传输层协议。 三、MySocket...

    java网络包全解析

    ##### Socket详解 **Socket** 类提供了创建客户端Socket的功能,它代表了一个TCP/IP连接的客户端部分。主要分为以下几部分: 1. **构造方法**: - 构造一个连接到指定主机和端口的Socket。 - 构造一个未连接的...

    linux下heartbeat3.04编译安装步骤.docx

    ### Linux 下 Heartbeat 3.04 编译安装及配置详解 #### 一、Heartbeat 3.04 概述 Heartbeat 是一款开源的高可用性集群管理工具,用于实现服务器间的故障切换和服务恢复。Heartbeat 3.04 相较于之前的版本有了较大的...

Global site tag (gtag.js) - Google Analytics