易语言 关于服务端检查客户端是否在线的心跳包问题
在客户端添加一个线程,用来发送在线的心跳包(此包生成的为时间戳,加密),服务器收到后,自动更新当前在线用户的在线时间
服务器添加一个线种,定时循环检测用户的时间戳,如果大于或小于设定时间(一般在30秒至1分钟)即判断为掉线并做掉线处理;
客户端防故意断网,如果发送信息失败,即断网
IM即时通讯开发如何实现Android版智能心跳机制。
大体思路
a)延迟心跳测试法:这是测试结果准确的前提保障,我们认为长连接建立后连续三次成功的短心跳就可以很大程度的保证下一次心跳环境是正常的。
b)成功一次认定,失败连续累积认定:成功是绝对的,连续失败多次才可能是失败。
c)临界值避免:我们使用比计算出的心跳稍微小一点的值做为稳定心跳避免临界值。
d)动态调整:即使在一次完整的智能心跳计算过程中,我们没有找到最好的值,我们还有机会来进行校正。
方案需考虑到影响连接寿命的思素
在Android下,不管是GCM,还是微信,都是通过TCP长连接来进行消息收发的,TCP长连接存活,消息收发就及时,所以要对影响TCP连接寿命的因素进行研究。
1、NAT超时
大部分移动无线网络运营商都在链路一段时间没有数据通讯时,会淘汰 NAT 表中的对应项,造成链路中断(NAT超时的更多描述见附录91)。NAT超时是影响TCP连接寿命的一个重要因素(尤其是国内),所以客户端自动测算NAT超时时间,来动态调整心跳间隔,是一个重要的优化点。
2、DHCP的租期 (lease time)
目前测试发现安卓系统对DHCP的处理有Bug,DHCP租期到了不会主动续约并且会继续使用过期IP,这个问题会造成TCP长连接偶然的断连。(租期问题的具体描述见附录92)。
3、网络状态变化
手机网络和WIFI网络切换、网络断开和连上等情况有网络状态的变化,也会使长连接变为无效连接,需要监听响应的网络状态变化事件,重新建立Push长连接。
心跳范围选择
1、前后台区分处理:
为了保证微信收消息及时性的体验,当微信处于前台活跃状态时,使用固定心跳。微信进入后台(或者前台关屏)时,先用几次最小心跳维持长链接。然后进入后台自适应心跳计算。这样做的目的是尽量选择用户不活跃的时间段,来减少心跳计算可能产生的消息不及时收取影响。
2、后台自适应心跳选择区间:
可根据自身产品的特点选择合适的心跳范围。
自适应心跳算法量化描述
因为每个网络的NAT时间可能不一致。所以需要区分计算,数据网络按subType做关键字,WIFI按WIFI名做关键字。对稳定的网络,因为NAT老化时间的存在,在自适应计算态的时候,暂设计以下步骤在当前心跳区间逼近出最大可用的心跳。 即时通讯聊天软件app开发可以加蔚可云的v:weikeyun24咨询
a)变量说明:
[MinHeart,MaxHeart]——心跳可选区间。
successHeart——当前成功心跳,初始为MinHeart
curHeart——当前心跳初始值为successHeart
heartStep——心跳增加步长
successStep——稳定期后的探测步长
经过该流程,会找到必然使心跳失败的curHeart(或者MaxHeart),为了保险起见,我们选择比前一个成功值稍微小一点的值作为后台稳定期的心跳间隔。
影响手机网络测试的因素太多,为了尽量保证测试结果的可靠性,我们使用延迟心跳测试法。在我们重新建立TCP连接后,先使用 短心跳连续成功三次,我们才认为网络相对稳定,可以使用curHeart进行一次心跳测试。图4-2显示了一次有效心跳测试过程。图4-3显示了在没有达到稳定网络环境时,我们会一直使用固定短心跳直到满足三次连续短心跳成功。
使用延迟心跳测试的好处是,可以剔除偶然失败,和网络变化较大的情况(如地铁),使测试结果相对可靠(五次延迟测试确定结论)。同时在网络波动较大的情况,使用短心跳,保证收取消息相对及时。
c)运行时的动态调整策略(已经按测算心跳稳定值后)
NAT超时值算出来后,在维持心跳的过程中的策略。
- 无网络、网络时好时坏、偶然失败、NAT超时变小:
在后台稳定期发生心跳发生失败后,我们使用延迟心跳测试法测试五次。如果有一次成功,则保持当前心跳值不变;如果五次测试全失败,重新计算合理心跳值。该过程如图4-4所示,有一点需要注意,每个新建的长连接需要先用短心跳成功维持3次后才用successHeart进行心跳。
NAT超时变大:
以周为周期,每周三将后台稳定态调至自适应计算态,使用心跳延迟法往后探测心跳间隔。
- successHeart是NAT超时临界值:
因为我们现在选择的是一个比successHeart稍小的值作为稳定值,所以在计算过程中可以避开临界值。当运营商在我们后台稳定期将NAT超时调整为我们当前计算值,那么由于我们每周会去向下探索,所以下一周探测时也可以及时调整正确。
d)冗余Sync和心跳
在用户的一些主动操作以及联网状态改变时,增加冗余Sync和心跳,确保及时收到消息。
1、当用户点亮屏幕的时候,做一次心跳。
2、当微信切换到前台时,做一次Sync。
3、联网时重建信令TCP,做一次Sync。
可能存在的风险及预防措施
DHCP租期因素:
1、问题:根据目前的测试结果显示,安卓不续约到期的IP Bug,会导致TCP连接在不确定的时间点失效,从而会导致一次心跳失败。
2、预防:统计后台稳定期的心跳成功率,上报给后台。后台可以按地区分网络监控这个指标的波动,并且后台可以根据不同的波动,动态调整某区域特定网络下可选的心跳区间。
NAT超时介绍
因为 IP v4 的 IP 量有限,运营商分配给手机终端的 IP 是运营商内网的 IP,手机要连接 Internet,就需要通过运营商的网关做一个网络地址转换(Network Address Translation,NAT)。简单的说运营商的网关需要维护一个外网 IP、端口到内网 IP、端口的对应关系,以确保内网的手机可以跟 Internet 的服务器通讯。
解决方法:下面是客户端心跳包核心代码:# region ++++++++++++++++++++ 客户端的感觉系统 //启动记时器 public void BeginTheTimer() { //th_UserLogin(); //这里只是要一个object类型数据,用它做为下面Timer的参数之一,没有其它意思 object myobject = (object)7; //暂时设定为1秒钟启动一次! SystemThreadingTimer t = new SystemThreadingTimer (new SystemThreadingTimerCallback(testTheNet), myobject, 1000, 1000); } //启动监视"已登录用户通信情况"的线程 public void testTheNet(object myobject) { //UserPassport up=new UserPassport(); Thread sendMyPulseThPro = new Thread(new ThreadStart(delegateSendMyPulse)); sendMyPulseThProStart(); } /// <summary> /// 每隔1秒就是要来做这些事情的 /// </summary> public void delegateSendMyPulse() { loginServer lser = new loginServer(); Login l = new Login(); lId = lserMyLoginId; lClientTypeVersion = version; lRequestType = 3; //3是确认联接正常的一个信号(让服务知道它与服务器的联接是正常的) loginServer lserver = new loginServer(); //启动一个新线程去发送数据 Thread thSendDat2 = new Thread (new ParameterizedThreadStart(lserverdelgSendDataMethod)); thSendDat2Start(l); thSendDat2IsBackground = true; //标记我已经发送出去一次数据了 longinserverMyLostTime += 1; //如果外发了3次请求暗号后仍不见服务器的回应,则认为客户端已经与服务器断开联系了 if(longinserverMyLostTime>=3) { //停止Timer //告诉用户:“你已经与服务器失去联系了…………” longinserverControls["txtShowMsg"]Text = "You have lost the connect!"; } }# endregion +++++++++++++++++++++ 客户端的感觉系统下面是服务器端核心代码如下:# region +++++++++++++++++++++++ 服务器的感觉系统 //启动记时器 public void LoadTheTimer() { object o=(object)loginedCount++; UserPassport up = new UserPassport(); //暂时设定为1秒钟启动一次! SystemThreadingTimer t = new SystemThreadingTimer (new SystemThreadingTimerCallback(watchTheLoginUser), o, 1000, 1000); } //启动监视"已登录用户通信情况"的线程 public void watchTheLoginUser(object o) { //UserPassport up=new UserPassport(); Thread checktheloginuser = new Thread(new ThreadStart(iAmAWatcher)); checktheloginuserStart(); } //真正做事的工人:这个工人的使命是每隔1秒钟后就查看一下登记薄 //registry里面有谁没有定时来向服务器报到了,如果出现谁三次检查都没有签到则除之名 public void iAmAWatcher() { thistxtLoginText += "@+"; int index = 0; for (index = 0; index < loginedCount; index++) { if (myRegistry[index]alive==false&®istry[index]studentID!="") { lock(this) { //坏(未到)记录增加一次 myRegistry[index]no_check_in_count += 1; if (myRegistry[index]no_check_in_count >= 3) { //thislblShowMsgText = "the student" //thislblShowMsgText += registry[index]studentIDToString() //thislblShowMsgText += "is diaoxianle!"; thistxtLoginText += "88"; //标记该人已经与服务器失去连接了,因为他有连续3次的未到记录存在 registry[index]studentID = ""; registry[index]StudentName = ""; registry[index]StudentIP = ""; registry[index]status = 2; //掉线 } } } } } //定时检查在线人目前状态# endregion +++++++++++++++++++ 服务器的感觉系统 本文来自CSDN博客,转载请标明出处: http://blogcsdnnet/QGJava/archive/2010/07/19/5745776aspx
对于openssh心跳报文的格式解析,我需要说明格式+解释原因+拓展内容。
心跳报文是一种用于维持连接活跃状态的通信报文。在openssh中,心跳报文的格式如下:
| Packet length | Padding length | Payload |
|--------------|----------------|---------|
| 2 | 1 | Variable|
- Packet length:指示整个报文的长度,占用2个字节。
- Padding length:指示报文中填充的字节数,占用1个字节。
- Payload:报文的有效载荷,可以是任意数据,长度不固定。
解释原因:心跳报文的格式设计是为了确保连接的活跃性和稳定性。通过定期发送心跳报文,可以使连接保持活跃状态,防止连接因为长时间没有通信而断开。报文中的长度字段和填充字段的设计,可以用于检测和处理传输中的错误或异常情况。
拓展内容:除了格式解析,还可以进一步拓展有关openssh心跳报文的相关知识。例如,心跳报文的发送频率可以根据实际需求进行调整,以平衡网络资源和连接稳定性。此外,心跳报文也可能存在一些安全风险,如心脏出血漏洞(Heartbleed vulnerability),攻击者可以利用该漏洞从目标服务器中获取敏感信息。因此,在使用openssh心跳功能时,需要注意安全性并及时更新软件版本以修复可能存在的漏洞。
建议客户端发送心跳包较为合适,原因:
1、若用户较多,服务端发送心跳包易使服务器超负荷。
2、客户端发送请求数据时可视为一次心跳包发送,节约处理速度。
3、客户端发送失败可立刻选择自动退出,服务端发送需要给客户端设置一个较长的等待时间,响应异常情况速度变慢。
当然客户端发送容易被篡改数据等,此处需要根据实际情况考虑。
心跳包的发送通常有两种技术方法。应用层自己实现的心跳包由应用程序自己发送心跳包来检测连接是否正常,大致的方法是服务器在一个Timer事件中定时向客户端发送一个短小精悍的数据包,然后启动一个低级别的线程,在该线程中不断检测客户端的回应,如果在一定时间内没有收到客户端的回应,即认为客户端已经掉线,同样,如果客户端在一定时间内没有收到服务器的心跳包,则认为连接不可用。
0条评论