如何在socket编程的Tcp连接中实现心跳协议
from http://blog.csdn.net/nyist327/article/details/39586203
方法1:应用层自己实现的心跳包
由应用程序自己发送心跳包来检测连接是否正常,大致的方法是:服务器在一个 Timer事件中定时 向客户端发送一个短小精悍的数据包,然后启动一个低级别的线程,在该线程中不断检测客户端的回应, 如果在一定时间内没有收到客户端的回应,即认为客户端已经掉线;同样,如果客户端在一定时间内没 有收到服务器的心跳包,则认为连接不可用。
方法2:TCP的KeepAlive保活机制
因为要考虑到一个服务器通常会连接多个客户端,因此由用户在应用层自己实现心跳包,代码较多 且稍显复杂,而利用TCP/IP协议层为内置的KeepAlive功能来实现心跳功能则简单得多。 不论是服务端还是客户端,一方开启KeepAlive功能后,就会自动在规定时间内向对方发送心跳包, 而另一方在收到心跳包后就会自动回复,以告诉对方我仍然在线。 因为开启KeepAlive功能需要消耗额外的宽带和流量,所以TCP协议层默认并不开启KeepAlive功 能,尽管这微不足道,但在按流量计费的环境下增加了费用,另一方面,KeepAlive设置不合理时可能会 因为短暂的网络波动而断开健康的TCP连接。并且,默认的KeepAlive超时需要7,200,000 MilliSeconds, 即2小时,探测次数为5次。对于很多服务端应用程序来说,2小时的空闲时间太长。因此,我们需要手工开启KeepAlive功能并设置合理的KeepAlive参数。
以上转自网络。
在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE。系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。
心跳包一般来说都是在逻辑层发送空的echo包来实现的。下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线了。
其实,要判定掉线,只需要send或者recv一下,如果结果为零,则为掉线。但是,在长连接下,有可能很长一段时间都没有数据往来。理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更要命的是,有的节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉。在这个时候,就需要我们的心跳包了,用于维持长连接,保活。
在获知了断线之后,服务器逻辑可能需要做一些事情,比如断线后的数据清理呀,重新连接呀……当然,这个自然是要由逻辑层根据需求去做了。
总的来说,心跳包主要也就是用于长连接的保活和断线处理。一般的应用下,判定时间在30-40秒比较不错。如果实在要求高,那就在6-9秒。
1客户端每隔一个时间间隔发生一个探测包给服务器
2客户端发包时启动一个超时定时器
3服务器端接收到检测包,应该回应一个包
4如果客户机收到服务器的应答包,则说明服务器正常,删除超时定时器
5如果客户端的超时定时器超时,依然没有收到应答包,则说明服务器挂了
转自:http://blog.sina.com.cn/s/blog_a459dcf5010153m5.html
根据上面的介绍我们可以知道对端以一种非优雅的方式断开连接的时候,我们可以设置SO_KEEPALIVE属性使得我们在2小时以后发现对方的TCP连接是否依然存在。
具体操作:
//设置KeepAlive
1、 BOOL bKeepAlive = TRUE;
int nRet=::setsockopt(sockClient,SOL_SOCKET,SO_KEEPALIVE,(char*)&bKeepAlive,sizeof(bKeepAlive));
if(nRet!=0)
{
AfxMessageBox("出错");
return ;
}
2、感觉两小时时间太长可以自行设定方法1
//设置KeepAlive检测时间和次数
tcp_keepalive inKeepAlive = {0}; //输入参数
unsigned long ulInLen = sizeof(tcp_keepalive );
tcp_keepalive outKeepAlive = {0}; //输出参数
unsigned long ulOutLen = sizeof(tcp_keepalive );
unsigned long ulBytesReturn = 0;
//设置socket的keep alive为10秒,并且发送次数为3次
inKeepAlive.onoff = 1;
inKeepAlive.keepaliveinterval = 4000; //两次KeepAlive探测间的时间间隔
inKeepAlive.keepalivetime = 1000; //开始首次KeepAlive探测前的TCP空闭时间
nRet=WSAIoctl(sockClient,
SIO_KEEPALIVE_VALS,
(LPVOID)&inKeepAlive,
ulInLen,
(LPVOID)&outKeepAlive,
ulOutLen,
&ulBytesReturn,
NULL,
NULL);
if(SOCKET_ERROR == nRet)
{
AfxMessageBox("出错");
return;
}
3、感觉两小时时间太长可以自行设定方法2
因此我们可以得到
int keepIdle = 6;
int keepInterval = 5;
int keepCount = 3;
Setsockopt(listenfd, SOL_TCP, TCP_KEEPIDLE, (void *)&keepIdle, sizeof(keepIdle));
Setsockopt(listenfd, SOL_TCP,TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
Setsockopt(listenfd,SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));
详见:http://blog.csdn.net/gavin1203/article/details/5290609
对setsockopt的操作,详见:http://www.cnblogs.com/hateislove214/archive/2010/11/05/1869886.html
如何在socket编程的Tcp连接中实现心跳协议的更多相关文章
- WPF中使用定时器 DispatcherTimer 做TCP连接中的心跳 HeartBeat
开发过程中经常遇到定时触发的需求,如:TCP/IP连接中,使用心跳包保持连接或检测连接是否已经中断. WPF中有多种定时器: 1.using System.Windows.Threading; 代码如 ...
- 几种TCP连接中出现RST的情况(转载)
TCP RST 网络 linux 目录[-] 1 端口未打开 2 请求超时 3 提前关闭 4 在一个已关闭的socket上收到数据 总结 参考文献: 应该没有人会质疑,现在是一个网络时代了.应该不少程 ...
- 计算机网络(十三),Socket编程实现TCP和UDP
十三.Socket编程实现TCP和UDP 1.TCP (1)TCPServer.java类 package com.interview.javabasic.socket; import com.int ...
- TCP连接中time_wait在开发中的影响-搜人以鱼不如授之以渔
根据TCP协议定义的3次握手断开连接规定,发起socket主动关闭的一方socket将进入TIME_WAIT状态,TIME_WAIT状态将持续2个MSL(Max Segment Lifetime),T ...
- tcp连接的状态变迁以及如何调整tcp连接中处于time_wait的时间
一.状态变迁图 二.time_wait状态 针对time_wait和close_wait有个简单的描述帮助理解: Due to the way TCP/IP works, connections ca ...
- 修改Linux内核参数,减少TCP连接中的TIME-WAIT
一台服务器CPU和内存资源额定有限的情况下,如何提高服务器的性能是作为系统运维的重要工作.要提高Linux系统下的负载能力,当网站发展起来之后,web连接数过多的问题就会日益明显.在节省成本的情况下, ...
- 【NodeJs】Ctrl+C在Linux平台和Windows平台下的TCP连接中的不同表现
Linux平台:CentOS release 6.5 (Final) Windows平台:Windows 7 旗舰版 服务器端代码如下: var net = require('net'); var s ...
- 服务器TCP连接中 TIME_WAIT 状态过多
今天查看服务器的TCP连接数,发现其中 TIME_WAIT 状态的太多了: # netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a ...
- TCP/IP详解--TCP连接中TIME_WAIT状态过多
TIMEWAIT状态本身和应用层的客户端或者服务器是没有关系的.仅仅是主动关闭的一方,在使用FIN|ACK|FIN|ACK四分组正常关闭TCP连接的时候会出现这个TIMEWAIT.服务器在处理客户端请 ...
随机推荐
- sql 循环语句几种方式(变量循环,游标循环,事务)
--第一 ) ,),Orders )) declare @n int,@rows int --select @rows=count(1) from pe_Orders select @rows = ...
- artDialog4.1.7 摘自网络
jquery.artDialog.source.js学习 1 关键的对象关系 art = jQuery = $ function artDialog() {...} artDialog.fn = ar ...
- Centos: -bash: unzip: command not found
安装命令:yum install -y unzip zip 同时安装unzip和zip
- mybatis SQL构造器
org.apache.ibatis.jdbc.AbstractSQL<T> org.apache.ibatis.jdbc.AbstractSQL<T> 抽象泛型类,它主要用于解 ...
- nodejs mysql 执行多条sql语句
执行多条查询语句 为了安全起见,默认情况下是不允许执行多条查询语句的.要使用多条查询语句的功能,就需要在创建数据库连接的时候打开这一功能: var connection = mysql.createC ...
- Linux系统运维笔记(二),Linux文件编辑命令
Linux系统运维笔记 Linux文件编辑命令 首先我们使用命令 vi filename 打开一个文件,这个时候进入到的是命令模式 接下来我们按i,然后键盘随便输入写内容. 然后按ESC重新进入到命令 ...
- Angular 5项目
Angular 5项目 如果您正在使用angular, 但是没有好好利用angular cli的话, 那么可以看看本文. Angular CLI 官网: https://github.com/angu ...
- Android导入依赖appcompat-v7报错
Android导入依赖appcompat-v7报错 导入appcompat-v7时报错了 导入的是implementation 'com.android.support:appcompat-v7: ...
- 008.KVM-VNC管理
一 VNC管理 1.1 修改配置 [root@kvm-host ~]# vi /etc/libvirt/qemu.conf …… vnc_listen = "0.0.0.0" 说明 ...
- python 函数式编程学习笔记
函数基础 一个函数就是将一些语句集合在一起的部件,它们能够不止一次地在程序中运行.函数的主要作用: 最大化的代码重用和最小化代码冗余 流程的分解 一般地,函数讲的流程是:告诉你怎样去做某事,而不是让你 ...