说起网络应用编程,想到最多的就是聊天类的软件。当然,在这类软件中,一般都会有一个用户掉线检测功能。今天我们就通过使用自定义的HeartBeat方式来检测用户的掉线情况。

心跳包实现思路

我们采用的思路是:客户端连接上服务端以后,服务端维护一个在线用户字典,客户端每隔一段时间,向服务器发送一个心跳包,服务器接收到包以后,字典数据的值都会更新为0;一旦服务端超过规定时间没有接收到客户端发来的包,字典数据将会递增加一,当字典数据的值累计大于等于三,则视为掉线。

代码逻辑

客户端每隔一段时间,发送一个心跳包:

#region 心跳Timer计数事件
private void heartbeatTimer_Tick(object sender, EventArgs e)
{
currentCount++;
if (currentCount == heartbeatCount)
{
txtMessage.Append("开始发送心跳包");
MessageEntity entity = new MessageEntity();
entity.MessageType = MessagePicks.Heartbeat;
entity.NickName = loginName; WriteToStream(entity);
currentCount = ;
}
}
#endregion

在服务端,会开启一个定时器,定时将userOnLineCounter中的值递增加一。如果此时收到客户端的心跳包,则将userOnLineCounter中的值重置。

 private void heartbeatTimer_Tick(object sender, EventArgs e)
{
tickCountInStep++;
if (tickCountInStep == tickCount)
{
if (userCollection.Count > )
{
//计数器自动递增
expiryCountInStep++;
foreach (User user in userLists)
{
userOnLineCounter[user]++;
}
//连续监测三次之后,开始监测集合中的掉线情况
if (expiryCountInStep == expiryCount)
{
//寻找集合中“掉线”的用户
var disconnectedUsers = userOnLineCounter.Where(p => p.Value >= ).ToList();
foreach (var disconnectedUser in disconnectedUsers)
{
txtLog.Append("用户" + disconnectedUser.Key.name + "掉线!"); //删除集合中被视为掉线的用户
userLists.Remove(disconnectedUser.Key);
userOnLineCounter.Remove(disconnectedUser.Key); //开始广播发送掉线用户
MessageEntity entity = new MessageEntity();
entity.MessageType = MessagePicks.OffLine;
EndPoint curOfflineUserEP = disconnectedUser.Key.client.Client.RemoteEndPoint;
string userName = disconnectedUser.Key.name;
entity.MessageContentEx.Add(curOfflineUserEP, userName); ObjectInversion inversion = new ObjectInversion();
byte[] byteArr = inversion.SerializeTo((object)entity); try
{
foreach (User user in userLists)
{
user.writer.Write(byteArr);
user.writer.Flush();
}
}
catch { }
}
expiryCountInStep = ;
}
}
tickCountInStep = ;
}
}
}

收到客户端心跳包,自动重置计数器。

case MessagePicks.Heartbeat:
txtLog.Append("收到客户端" + entity.NickName + "的心跳回应包.");
if (userOnLineCounter.ContainsKey(user))
userOnLineCounter[user] = ;
else
userOnLineCounter.Add(user, );
break;

效果图

(图1:三个客户端连接一个服务器)

(图2:用户“上善若水”掉线)

(图3:用户“古道热肠”掉线)

程序暂时还未完全完成,有需要的可以参考下。当然也期待大家的各种思路。

代码很丑,期望大家指点下重构的方法。

源码下载

点击这里下载

=====================2014年9月24日重构版本=======================

用户实体内部通过维护一个timer计数器,实现心跳检测,心跳超时功能。

点击这里下载新版

TCP之心跳包实现思路的更多相关文章

  1. Tcp之心跳包

    Tcp之心跳包 心跳包 跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着. 事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很 ...

  2. TCP socket心跳包示例程序

    在做游戏开发时,经常需要在应用层实现自己的心跳机制,即定时发送一个自定义的结构体(心跳包),让对方知道自己还活着,以确保连接的有效性. 在TCP socket心跳机制中,心跳包可以由服务器发送给客户端 ...

  3. Socket之心跳包实现思路

    由于最近要做一个客户端,但是要求有一个掉线检测的功能,下面让我们看看使用自定义的HeartBeat方式来检测客户端的连接情况. 心跳包的实现思路: 客户端连接上服务端后,在服务端会维护一个在线客户端列 ...

  4. 闲说HeartBeat心跳包和TCP协议的KeepAlive机制

    很多应用层协议都有HeartBeat机制,通常是客户端每隔一小段时间向服务器发送一个数据包,通知服务器自己仍然在线,并传输一些可能必要的数据.使用心跳包的典型协议是IM,比如QQ/MSN/飞信等协议. ...

  5. TCP连接探测中的Keepalive和心跳包

    TCP连接探测中的Keepalive和心跳包 tcp keepalive 心跳 保活 Linuxtcp心跳keepalive保活1. TCP保活的必要性 1) 很多防火墙等对于空闲socket自动关闭 ...

  6. TCP连接探测中的Keepalive 和心跳包

    采用TCP连接的C/S模式软件,连接的双方在连接空闲状态时,如果任意一方意外崩溃.当机.网线断开或路由器故障,另一方无法得知TCP连接已经失效,除非继续在此连接上发送数据导致错误返回.很多时候,这不是 ...

  7. TCP连接探测中的Keepalive和心跳包. 关键字: tcp keepalive, 心跳, 保活

    1. TCP保活的必要性 1) 很多防火墙等对于空闲socket自动关闭 2) 对于非正常断开, 服务器并不能检测到. 为了回收资源, 必须提供一种检测机制. 2. 导致TCP断连的因素 如果网络正常 ...

  8. tcp/心跳包

    1,http://blog.csdn.net/yuzhiyuxia/article/details/7857508 心跳包就是在客户端和服务器间定时通知对方自己状态的一个自己定义的命令字,按照一定的时 ...

  9. TCP/UDP区别&&心跳包机制【转】

    转自:https://www.jianshu.com/p/6d93a3c21c34 UDP:用户数据报协议:主要用在实时性要求比较高的以及对质量相对较弱的地方.但是面对现在高质量的线路不会容易丢包,除 ...

随机推荐

  1. iOS开发之网络编程--3、NSURLSessionDataTask实现文件下载(离线断点续传下载)

    前言:使用NSURLSessionDownloadTask满足不这个需要离线断点续传的下载需求,所以这里就需要使用NSURLSessionDataTask的代理方法来处理下载大文件,并且实现离线断点续 ...

  2. MySQL学习基础 之 起航篇

    MySQL 学习来自慕课网<与MySQL的零距离接触> MySQL是一个开源的关系型数据库管理系统 MySQL分为社区版和企业版 MySQL登录和退出相关的命令 参数 描述 -D,--da ...

  3. Objective-C的可变是如何实现的?

    Objective-C的可变是怎么实现的?      

  4. 二维码扫描利用ZBar实现

    上次是根据系统的属性自己封装的一个二维码扫描,这次给大家介绍一下基于ZBar集成的类似于QQ二维码扫描界面的二维码扫描的效果.                                     ...

  5. sql 存储过程中top 后面跟参数的问题

    之前存储过程中有top的情况,都是拼接sql,然后通过exec执行,进行查询结果,很不方便. 今天研究了,原来top后面是可以直接写参数的. 只需要top 后面的参数加上小括号就好了 eg: TOP ...

  6. CentOS 7 安装Docker

    1.安装前检查: a.内核版本 uname -a b.检查Device Mapper ls -l /sys/class/misc/device-mapper 2.安装Docker: a.更新系统包到最 ...

  7. SQL中获取最近的N个半年度

    直接上代码: --获取往前推的N个半年度 CREATE FUNCTION F3_GetRecentNHalfYear ( @N INT ) RETURNS @Result TABLE ( Year S ...

  8. 烂泥:LVM学习之逻辑卷、卷组及物理卷删除

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 上篇文章,我们介绍了有关LVM的逻辑卷及卷组的空间缩小.这次我们来介绍下如何删除一个逻辑卷及卷组. 删除逻辑卷需要以下几个步骤: 1. 卸载已经挂载的逻 ...

  9. gdb调试常用命令

    gdb 调试常用命令 gcc -g mian.c -o main.out -o (定制生成的可执行文件的名称,缺省时为a.out) -g 使gdb可调试,在编译的时候,产生调试信息 gdb main. ...

  10. Web Storage API : LocalStroage

    这是一篇详细介绍详细介绍详细介绍_(:з」∠)_ 背景: 当你访问一个页面,并不是丢到服务器,等待用户访问就可以了的.从输入网址到显示网页的全过程,可以参考这里 简单来说,在输入url按下回车键后,首 ...