Socket心跳包机制

<div id="article_content" class="article_content">


<div id="sina_keyword_ad_area2" class="articalContent  ">
<div><span style="font-family:Verdana,Geneva,Arial,Helvetica,sans-serif; font-weight:bold"><span style="color:#FF0000"><span style="color:#000000">心跳包的发送,通常有两种技术</span><br>
方法1:应用层自己实现的心跳包 </span><br>
由应用程序自己发送心跳包来检测连接是否正常,大致的方法是:服务器在一个 Timer事件中定时 向客户端发送一个短小精悍的数据包,然后启动一个低级别的线程,在该线程中不断检测客户端的回应, 如果在一定时间内没有收到客户端的回应,即认为客户端已经掉线;同样,如果客户端在一定时间内没 有收到服务器的心跳包,则认为连接不可用。<br>
<br>
<span style="font-family:Verdana,Geneva,Arial,Helvetica,sans-serif"><span style="color:#FF0000">方法2:TCP的KeepAlive保活机制</span><br>
因为要考虑到一个服务器通常会连接多个客户端,因此由用户在应用层自己实现心跳包,代码较多 且稍显复杂,而利用TCP/IP协议层为内置的KeepAlive功能来实现心跳功能则简单得多。 不论是服务端还是客户端,一方开启KeepAlive功能后,就会自动在规定时间内向对方发送心跳包, 而另一方在收到心跳包后就会自动回复,以告诉对方我仍然在线。 因为开启KeepAlive功能需要消耗额外的宽带和流量,所以TCP协议层默认并不开启KeepAlive功 能,尽管这微不足道,但在按流量计费的环境下增加了费用,另一方面,KeepAlive设置不合理时可能会
 因为短暂的网络波动而断开健康的TCP连接。并且,默认的KeepAlive超时需要7,200,000 MilliSeconds, 即2小时,探测次数为5次。对于很多服务端应用程序来说,2小时的空闲时间太长。因此,我们需要手工开启KeepAlive功能并设置合理的KeepAlive参数。<br>
<span style="font-family:Verdana,Geneva,Arial,Helvetica,sans-serif">以上转自网络<span style="font-family:Verdana,Geneva,Arial,Helvetica,sans-serif">。</span></span><br>
<br>
</span><br>
<br>
<a href="http://www.cppblog.com/tx7do/archive/2009/11/09/100513.html" name="viewpost1_TitleUrl"><span style="color:#ED1C24">心跳包机制</span></a></span></div>
<div><span style="word-spacing:0px; font:14px/23px simsun; text-transform:none; color:rgb(0,0,0); text-indent:0px; white-space:normal; letter-spacing:normal; background-color:rgb(255,255,255); text-align:left; orphans:2; widows:2"><span style="color:#000000; word-spacing:0px; font:medium simsun; text-transform:none; text-indent:0px; white-space:normal; letter-spacing:normal; border-collapse:separate; orphans:2; widows:2"><span style="font-family:simsun; font-size:14px; line-height:23px">&nbsp;<wbr>&nbsp;<wbr>跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。<br>
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE。系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。<br>
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>心跳包一般来说都是在逻辑层发送空的echo包来实现的。下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线了。<br>
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>其实,要判定掉线,只需要send或者recv一下,如果<span style="color:#ED1C24">结果为零,则为掉线</span>。但是,在长连接下,有可能很长一段时间都没有数据往来。理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更要命的是,有的<span style="color:#FF0000">节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉</span>。在这个时候,就需要我们的心跳包了,用于维持长连接,保活。<br>
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>在获知了断线之后,服务器逻辑可能需要做一些事情,比如断线后的数据清理呀,重新连接呀……当然,这个自然是要由逻辑层根据需求去做了。<br>
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>总的来说,<span style="color:#ED1C24">心跳包主要也就是用于长连接的保活和断线处理</span>。一般的应用下,判定时间在30-40秒比较不错。如果实在要求高,那就在6-9秒。</span></span></span></div>
<div><span style="color:#000000; word-spacing:0px; font:14px/23px simsun; text-transform:none; text-indent:0px; white-space:normal; letter-spacing:normal; background-color:rgb(255,255,255); text-align:left; orphans:2; widows:2"><span style="color:#000000; word-spacing:0px; font:medium simsun; text-transform:none; text-indent:0px; white-space:normal; letter-spacing:normal; border-collapse:separate; orphans:2; widows:2"><span style="font-family:simsun; font-size:14px; line-height:23px"><br>
</span></span></span></div>
<div><span style="word-spacing:0px; font:14px/23px simsun; text-transform:none; color:rgb(0,0,0); text-indent:0px; white-space:normal; letter-spacing:normal; background-color:rgb(255,255,255); text-align:left; orphans:2; widows:2"><span style="word-spacing:0px; font:medium simsun; text-transform:none; color:rgb(0,0,0); text-indent:0px; white-space:normal; letter-spacing:normal; border-collapse:separate; orphans:2; widows:2"><span style="font-size:14px; line-height:23px; font-family:simsun"><font face="宋体,Verdana,Arial,Helvetica,sans-serif" style="line-height:21px"><span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5; font:normal normal normal 14px/23px simsun; background-color:rgb(255,255,255)"><span style="color:#ED1C24">心跳检测步骤</span>:</span><span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5; font:normal normal normal 14px/23px simsun; background-color:rgb(255,255,255)"><br style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5">
</span><span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5; font:normal normal normal 14px/23px simsun; background-color:rgb(255,255,255)">1客户端每隔一个时间间隔发生一个探测包给服务器</span><span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5; font:normal normal normal 14px/23px simsun; background-color:rgb(255,255,255)"><br style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5">
</span><span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5; font:normal normal normal 14px/23px simsun; background-color:rgb(255,255,255)">2客户端发包时启动一个超时定时器</span><span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5; font:normal normal normal 14px/23px simsun; background-color:rgb(255,255,255)"><br style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5">
</span><span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5; font:normal normal normal 14px/23px simsun; background-color:rgb(255,255,255)">3服务器端接收到检测包,应该回应一个包</span><span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5; font:normal normal normal 14px/23px simsun; background-color:rgb(255,255,255)"><br style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5">
</span><span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5; font:normal normal normal 14px/23px simsun; background-color:rgb(255,255,255)">4如果客户机收到服务器的应答包,则说明服务器正常,删除超时定时器</span><span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5; font:normal normal normal 14px/23px simsun; background-color:rgb(255,255,255)"><br style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5">
</span><font face="宋体,Verdana,Arial,Helvetica,sans-serif" style="line-height:1.5; font:normal normal normal 14px/23px simsun; background-color:rgb(255,255,255)">5如果客户端的超时定时器超时,依然没有收到应答包,则说明服务器挂了<br>
<font face="宋体,Verdana,Arial,Helvetica,sans-serif">转自:http://blog.sina.com.cn/s/blog_a459dcf5010153m5.html<br>
<br>
根据上面的介绍我们可以知道对端以一种非优雅的方式断开连接的时候,我们可以设置SO_KEEPALIVE属性使得我们在2小时以后发现对方的TCP连接是否依然存在。<br>
<font face="宋体,Verdana,Arial,Helvetica,sans-serif"><span style="background-color:rgb(255,255,51)"><span style="color:#FF0000">具体操作:</span></span><br>
&nbsp;&nbsp;&nbsp; //设置KeepAlive&nbsp;&nbsp;&nbsp; &nbsp;<br>
<span style="color:#FF0000">&nbsp;&nbsp; 1<span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif">、</span></span> BOOL&nbsp;&nbsp; bKeepAlive&nbsp;&nbsp; =&nbsp;&nbsp; TRUE;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;int nRet=::<span style="color:#FF0000">setsockopt</span>(sockClient,SOL_SOCKET,SO_KEEPALIVE,(char*)&amp;bKeepAlive,sizeof(bKeepAlive));&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;if(nRet!=0)&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AfxMessageBox("出错"); <br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return&nbsp;&nbsp; ;<br>
&nbsp;&nbsp; &nbsp;}&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;<br>
<span style="color:#FF0000">&nbsp;&nbsp; 2、感觉两小时时间太长可以自行设定方法1</span> <br>
//设置KeepAlive检测时间和次数&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;tcp_keepalive&nbsp;&nbsp;&nbsp; inKeepAlive&nbsp;&nbsp; =&nbsp;&nbsp; {0};&nbsp;&nbsp; //输入参数&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;unsigned&nbsp;&nbsp; long&nbsp;&nbsp; ulInLen&nbsp;&nbsp; =&nbsp;&nbsp; sizeof(tcp_keepalive );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;tcp_keepalive&nbsp;&nbsp;&nbsp; outKeepAlive&nbsp;&nbsp; =&nbsp;&nbsp; {0};&nbsp;&nbsp; //输出参数&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;unsigned&nbsp;&nbsp; long&nbsp;&nbsp; ulOutLen&nbsp;&nbsp; =&nbsp;&nbsp; sizeof(tcp_keepalive );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;unsigned&nbsp;&nbsp; long&nbsp;&nbsp; ulBytesReturn&nbsp;&nbsp; =&nbsp;&nbsp; 0;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;//设置socket的keep&nbsp;&nbsp; alive为10秒,并且发送次数为3次&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;inKeepAlive.onoff&nbsp;&nbsp; =&nbsp;&nbsp; 1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;inKeepAlive.keepaliveinterval&nbsp;&nbsp; =&nbsp;&nbsp; 4000;&nbsp;&nbsp; //两次KeepAlive探测间的时间间隔&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;inKeepAlive.keepalivetime&nbsp;&nbsp; =&nbsp;&nbsp; 1000;&nbsp;&nbsp; //开始首次KeepAlive探测前的TCP空闭时间&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;nRet=<span style="color:#FF0000">WSAIoctl</span>(sockClient,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;SIO_KEEPALIVE_VALS,&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;(LPVOID)&amp;inKeepAlive,&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ulInLen,&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;(LPVOID)&amp;outKeepAlive,&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ulOutLen,&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&amp;ulBytesReturn,&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;NULL,&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;NULL);&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;if(SOCKET_ERROR&nbsp;&nbsp; ==&nbsp;&nbsp; nRet)&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;AfxMessageBox("出错");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;}&nbsp;&nbsp; <br>
<span style="word-spacing:0px; font:14px/23px simsun; text-transform:none; color:rgb(0,0,0); text-indent:0px; white-space:normal; letter-spacing:normal; background-color:rgb(255,255,255); text-align:left; orphans:2; widows:2"><span style="word-spacing:0px; font:medium simsun; text-transform:none; color:rgb(0,0,0); text-indent:0px; white-space:normal; letter-spacing:normal; border-collapse:separate; orphans:2; widows:2"><span style="font-size:14px; line-height:23px; font-family:simsun"><span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:21px"><span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif; line-height:1.5; font:normal normal normal 14px/23px simsun; background-color:rgb(255,255,255)"><span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif"><span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif"><span style="color:#FF0000">3、感觉两小时时间太长可以自行设定方法<span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif">2<br>
<span style="color:#000000">因此我们可以得到<br>
&nbsp; &nbsp; int&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;keepIdle = 6;<br>
&nbsp; &nbsp; int&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;keepInterval = 5;<br>
&nbsp; &nbsp; int&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;keepCount = 3;<br>
&nbsp; &nbsp; Setsockopt(listenfd, SOL_TCP, TCP_KEEPIDLE, (void *)&amp;keepIdle, sizeof(keepIdle));<br>
&nbsp; &nbsp; Setsockopt(listenfd, SOL_TCP,TCP_KEEPINTVL, (void *)&amp;keepInterval, sizeof(keepInterval));<br>
&nbsp; &nbsp; Setsockopt(listenfd,SOL_TCP, TCP_KEEPCNT, (void *)&amp;keepCount, sizeof(keepCount));<br>
<br>
<span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif">详见:http://blog.youkuaiyun.com/gavin1203/article/details/5290609<br>
<span style="font-family:宋体,Verdana,Arial,Helvetica,sans-serif">对<strong>setsockopt</strong>的操作,详见:http://www.cnblogs.com/hateislove214/archive/2010/11/05/1869886.html</span><br>
<br>
</span></span></span></span></span></span></span></span></span></span></span></font></font></font></font></span></span></span></div>
</div>
   
</div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值