虽然我们前面已经介绍完了ESFramework开发所需掌握的各种基础设施,但是还不够。想要更好地利用ESFramework这一利器,有些背景知识是我们必须要理解的。就像本文介绍的心跳机制,在严峻的Internet条件下,是通信系统中不可或缺的机制之一。 在Internet上采用TCP进行通信的系统,都会遇到一个令人头疼的问题,就是“掉线”。而“TCP掉线”这个问题远比我们通常所能想象的要复杂的多 —— 网络拓扑纷繁复杂、而从始节点A到终节点B之间可能要经过N多的交换机、路由器、防火墙等等硬件设备,每个硬件设备的相关设定也不统一,再加上网络中可能出现的拥塞、延迟等,使得我们在编程时,处理掉线也非常棘手。 一.从程序的角度看待TCP掉线 TCP掉线的原因多种多样、不一而足,比如,客人的电脑突然断电、OS崩溃、路由器重启、网线接触不良、因为P2P下载软件而导致网络资源短缺、Internet网络的不稳定等等,但是从程序的角度来说,我们可以总结为两种情况:程序能立即感知的掉线和程序不能立即感知的掉线。 1. 程序能立即感知的掉线 也就是说客户端一掉线,服务器端的某个读写对应的TCP连接的线程就会抛出异常,这种情况相对容易处理。而ESFramework针对这种情况,会触发IUserManager的SomeOneDisconnected事件,来通知我们的应用程序。       ///<summary>   /// 客户端连接被关闭时,将触发此事件。不要远程预定该事件。   ///</summary>   event CbGeneric<UserData ,DisconnectedType> SomeOneDisconnected;  2. 程序不能立即感知的掉线 我们都知道,TCP连接的建立,需要经过三次握手;而TCP连接的断开,需要经过四次挥手。掉线通常没什么大不了的,掉就掉了呗,只要四次挥手顺利完成后,服务器和客户端分别做一些善后处理就可以。

麻烦的事情在于,连接在没有机会完成4次挥手时已经断开了(比如当客人的电脑系统死机,或客人电脑与服务器之间的某处物理网线断开),而服务端以为客户端还正常在线,而客户端也自以为还正常在线。这种程序对现实状态的错误判断有可能引发诸多悲剧。比如,在此情况下,客户端发一个指令给服务器,服务器因为没有收到而一直处于等待指令的状态;而客户端了,以为服务器已经收到了,也就一直处于等待服务端回复的状态。如果程序的其它部分需要依据当前的状态来做后续的操作,那就可能会出问题,因为程序对当前连接状态的判断是错误的。

毫无疑问,这种对连接状态错误的判断所持续的时间越久,带来可能的危害就越大。当然,如果我们不做任何额外的处理措施,服务器到最后也能感受到客户端的掉线,但是,这个时间可能已经过去了几分钟甚至几十分钟。对于大多数应用来说,这是不可忍受的。 所以,针对这种不能立即感知掉线的情况,我们要做的补救措施,就是帮助程序尽快地获知tcp连接已断开的信息。

首先,我们可以在Socket上通过Socket.IOControl方法设置KeepAliveValues,来控制底层TCP的保活机制,比如,设定2秒钟检测一次,超过10秒检测失败时抛出异常。  byte[] inOptionValues = FillKeepAliveStruct(1, 10000, 2000); socket.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);

ESFramework底层已经进行了如此处理。据我们的经验,这种设定可以解决一部分问题,但是仍然会有一些连接在断开后,远远超过10秒才被感知掉。所以,这个补救措施还是远远不够的。我们还需要在应用层加入我们自己的TCP连接状态检测机制,这种机制就是通常所说的“心跳”。 二."心跳"机制 心跳机制的原理很简单:客户端每隔N秒向服务端发送一个心跳消息,服务端收到心跳消息后,回复同样的心跳消息给客户端。如果服务端或客户端在M秒(M>N)内都没有收到包括心跳消息在内的任何消息,即心跳超时,我们就认为目标TCP连接已经断开了。

由于不同的应用程序对感知TCP掉线的灵敏度不一样,所以,N和M的值就可以设定的不一样。灵敏度要求越高,N和M就要越小;灵敏度要求越低,N和M就可以越大。而要求灵敏度越高,也是有代价的,那就是需要更频繁地发送心跳消息,如果有几千个连接同时频繁地发送心跳消息,那么其所消耗的资源也是不能忽略的。

当然,网络环境(如延迟的大小)的好坏,也对会对N和M的值的设定产生影响,比如,网络延迟较大,那么N与M之间的差值也应该越大(比如,M是N的3倍)。否则,可能会产生误判 -- 即TCP连接没有断开,只是因为网络延迟大才及时没收到心跳消息,我们却认为连接已经断开了。 ESFramework内置了心跳机制: 在服务端,可通过IRapidServerEngine的HeartbeatTimeoutInSecs属性来设置上面描述的M值。 在客户端,则通过IRapidPassiveEngine的HeartBeatSpanInSecs属性设置N值。 当心跳超时时,服务端会触发IUserManager的SomeOneTimeOuted事件,来通知我们的应用程序。     三.必须关闭掉线的TCP连接

无论是普通掉线(立即感知)还是心跳超时掉线(非立即感知),都需要关闭对应的TCP连接以释放系统资源。ESFramework将会自动帮我们关闭掉线的TCP连接。 另外要提醒一点,当TCP连接超时掉线时,服务端会引擎首先会触发IUserManager的SomeOneTimeOuted事件,接着再触发IUserManager的SomeOneDisconnected事件。 四.UDP与"心跳"

前面介绍的都是关于TCP的掉线的问题,下面我们看看UDP。 由于UDP是无连接的协议,所以,当我们在使用ESFramework的UDP引擎的时候,几乎肯定是需要配备心跳机制的,使用心跳消息确认客户端还在线,以保证服务端不会过早释放对应的Session或长期保留已失效的Session。      在ESFramework 开发手册(04) -- 可靠的P2P 一文中介绍的P2P通道如果是基于UDP的,则ESPlus内部也启动了心跳机制,以保证在基于UDP的P2P通道断开时,ESPlus能尽快感知,并关闭对应的P2P通道。 五.关闭心跳机制 比如,在LAN中进行通信的分布式系统,由于网络延迟和意外掉线的几率微乎其微,所以,可以考虑关闭心跳机制。再比如,当我们断点调试客户端程序时,由于断点时间太久,服务端会判断为客户端已经心跳超时掉线了,在这种情况下,也可以关闭心跳机制。那么如何关闭心跳机制了?可以这样做: 将IRapidPassiveEngine的HeartBeatSpanInSecs属性设置为0。这样客户端就不会发送定时的心跳消息了。 将IRapidServerEngine的HeartbeatTimeoutInSecs属性设置为小于等于0。这表示服务端将不再做心跳超时检查。

六.客户端如何快速感知自己掉线? 在某些客户端电脑上,比如拔掉网线,或断开wifi,程序可能需要几秒到几分钟才能感知到自己掉线,不同的电脑这个感受的时间不一样。那么如何才能让客户端尽可能快地得到掉线通知了?
可以利用socket写超时的机制,像下面这样做:
(1)将Socket发送缓冲区的大小设置为0。       对应IRapidPassiveEngine的Advanced属性的WriteTimeoutInSecs属性。
(2)设置写超时为一个较小的值,如30秒。      对应IRapidPassiveEngine的Advanced属性的SocketSendBuffSize属性。
这样,结合上面的心跳发送机制(如每隔5秒发送一个心跳),则当网络断开后,在发送心跳消息,最多再过30秒,程序就会得到掉线通知了。

http://blog.oraycn.com/ESFramework_07.aspx

ESFramework 开发手册(07) -- 掉线与心跳机制(转)的更多相关文章

  1. 判定生死的心跳机制 --ESFramework 4.0 快速上手(07)

    在Internet上采用TCP进行通信的系统,都会遇到一个令人头疼的问题,就是"掉线".而"TCP掉线"这个问题远比我们通常所能想象的要复杂的多 -- 网络拓扑 ...

  2. [心跳] 使用心跳机制实现CS架构下多客户端的在线状态实时更新以及掉线自动重连

    此文讲述的内容是一个实际项目开发中的一部分内容,笔者将亲身经历写成文章. [背景] 现 需要实现这样的功能:有多个客户端连着同一个服务器.服务器和客户端之间需要“互相”知道彼此的连接状态.比如在某一时 ...

  3. 使用心跳机制实现CS架构下多客户端的在线状态实时更新以及掉线自动重连

    此文讲述的内容是一个实际项目开发中的一部分内容,笔者将亲身经历写成文章. [背景] 现需要实现这样的功能:有多个客户端连着同一个服务器.服务器和客户端之间需要“互相”知道彼此的连接状态.比如在某一时刻 ...

  4. TCP长连接与短连接、心跳机制

    1. TCP连接 当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,连接的建立是需要三次 ...

  5. 基于netty实现的长连接,心跳机制及重连机制

    技术:maven3.0.5 + netty4.1.33 + jdk1.8   概述 Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速 ...

  6. [转]Android TCP长连接 心跳机制及实现

    背景知识 智能手机上的长连接心跳和在Internet上的长连接心跳有什么不同 Android系统的推送和iOS的推送有什么区别 几种推送的实现方式 协议 1XMPP简介 2 MQTT简介 3移动端消息 ...

  7. Netty学习篇④-心跳机制及断线重连

    心跳检测 前言 客户端和服务端的连接属于socket连接,也属于长连接,往往会存在客户端在连接了服务端之后就没有任何操作了,但还是占用了一个连接:当越来越多类似的客户端出现就会浪费很多连接,netty ...

  8. 《即时消息技术剖析与实战》学习笔记8——IM系统如何保证长连接的可用性:心跳机制

    假设有以下突发意外情况: 用户进入信号不好的地方,手机没有网络信号了 上网的路由器突然掉线了 这个时候,比如微信发消息,消息就会转圈圈,甚至变成红色叹号-- 上面情况都会导致"长连接&quo ...

  9. “嘭、嘭、嘭”---C/S架构下的心跳机制

    本人想使用AU3开发多客户端.一服务端.需要使用到心跳机制,即 在线状态实时更新以及掉线自动重连. 搜索网络发现没有人用AU3写心跳机制. 下面是一篇转帖(原文地址:http://www.cnblog ...

随机推荐

  1. js 常用正则表达式分析详解

    1.整数或者小数:/^((0{1}|[1-9]{1}[0-9]+)\.{1}[0-9]+|[1-9]{1}[0-9]*|0)$/ 分析:分类讨论,如果是小数,则有两种形式   0.111对应的是 0{ ...

  2. MFC TCHAR 和CHAR相互转换

    没有定义UNICODE,所以它里面的字符串就是简单用" "就行了,创建工程的时候包含了UNICODE定义,就必须对TCHAR和char进行转换. 首先是把TCHAR转为char / ...

  3. java垃圾回收那点事(二)不同gc策略的heap分配

    在前面的文章中曾提到了在java虚拟机启动的时候会对G1,CMS, SerialGC定义不同的heap的类,并且定义不同的policy. CollectorPolicy CollectorPolicy ...

  4. 【机器学习实验】学习Python来分类现实世界的数据

    引入 一个机器能够依据照片来辨别鲜花的品种吗?在机器学习角度,这事实上是一个分类问题.即机器依据不同品种鲜花的数据进行学习.使其能够对未标记的測试图片数据进行分类. 这一小节.我们还是从scikit- ...

  5. s nrmtyu,yi.sfn rt

    http://www.zhihu.com/collection/24337307 http://www.zhihu.com/collection/24337259 http://www.zhihu.c ...

  6. 阿里巴巴2015研究project普通笔试题,与答案

    欢迎您对这篇文章的其他建议.我可以留言在以下平台. 个人博客网站:www.anycodex.com/blog/ Csdn博客网站:http://my.csdn.net/?ref=toolbar 微博: ...

  7. Android中G-Sensor相关流程

    1.使G-sensor正常工作需要做的事: G-sensor driver文件包括: driver/i2c/chips/lis331dl.c driver/i2c/chips/sensorioctl. ...

  8. red hat Linux 使用CentOS yum源更新

    red hat linux是商业版软件,没有经过注册是无法使用红帽 yum源更新软件的,使用CentOS源更新操作如下: 1.删除red hat linux 原有的yum 源 rpm -aq | gr ...

  9. 【译】ASP.NET MVC 5 教程 - 3:添加视图

    原文:[译]ASP.NET MVC 5 教程 - 3:添加视图 在本节内容中,我们将修改HelloWorldController类,使用视图模板来干净利索的封装生成HTML响应客户端的过程. 您将创建 ...

  10. SWT中在treeview中显示图片

    package com.repositoryclient.treeview; import org.eclipse.jface.resource.ImageDescriptor; import org ...