项目分析:

  一个实时的IM坐席系统,客户端和坐席使用IM通信,客户端使用android和ios的app,坐席使用web。

  web端可以保留自己的登录状态,但为防止意外情况的发生(如浏览器异常关闭,断网,断电),对坐席的实时在线状态造成影响,我们在后台跑一个服务,实时向每个坐席发送一个心跳包,当坐席的状态是在线,但是又不能接收到服务端的心跳包的时候,认为该坐席已经被异常下线。

实时通信Signalr

  使用中发现signalr的服务端必须需要 .net frameword4.5及以上版本,对signalr使用了自行托管,使服务端和页面相互独立。

  配置过程:

控制台部分:
1. 用VS创建一个名为 "SignalRSelfHost" 的控制台项目
2. 在程序包管理器控制台,输入如下命令
   Install-Package Microsoft.AspNet.SignalR.SelfHost
3. 输入如下命令:
   Install-Package Microsoft.Owin.Cors
4. 控制台代码:

using Microsoft.AspNet.SignalR;
using Microsoft.Owin.Cors;
using Microsoft.Owin.Hosting;
using Owin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers; namespace SignalRSelfHost
{
class Program
{
static void Main(string[] args)
{
// This will *ONLY* bind to localhost, if you want to bind to all addresses
// use http://*:8080 to bind to all addresses.
// See http://msdn.microsoft.com/en-us/library/system.net.httplistener.aspx
// for more information.
string url = "http://localhost:8080";
using (WebApp.Start(url))
{
Console.WriteLine("Server running on {0}", url);
Console.ReadLine();
}
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
public class MyHub : Hub
{
public static List<User> onlineUsers = new List<User>();
public void Send(string name, string message)
{
Console.WriteLine("client messsage from ["+name+"],message:"+message);
//Clients.All.addMessage(name, "voip:[" + name+"],message:"+message);
var user = onlineUsers.Where(u => u.Voip == name).FirstOrDefault();
Clients.Client(user.ConnectionId).addMessage(user.ConnectionId, "voip:[" + name + "],message:" + message);
} public void LoginIn(string voip) {
var user = onlineUsers.Where(u => u.Voip == voip).FirstOrDefault();
if (user == null)
{
string connId = Context.ConnectionId;
user = new User
{
Voip = voip,
Second = ,
ConnectionId=connId
};
onlineUsers.Add(user);
Console.WriteLine(user.Voip + "上线了");
//Console.ReadLine();
user.HeartBeatAction += () =>
{
SendHeartBeat(connId);
};
user.LogoutAction += () =>
{
LoginOut(voip);
};
}
else {
user.HeartBeatAction += () =>
{
SendHeartBeat(user.ConnectionId);
};
user.LogoutAction += () =>
{
LoginOut(user.Voip);
};
Console.WriteLine(user.Voip + "已经在线了");
Console.ReadLine();
} } /// <summary>
/// 发送心跳包
/// </summary>
/// <param name="voip"></param>
private void SendHeartBeat(string connid)
{
Clients.Client(connid).recieveHeartBeat(connid);
// Clients.All.recieveHeartBeat(voip);
} /// <summary>
/// 接收心跳包
/// </summary>
/// <param name="id"></param>
public void RecieveHeartBeat(string connid)
{
var user = onlineUsers.Where(u => u.ConnectionId == connid).FirstOrDefault();
if (user == null) return;
user.Second = ; } /// <summary>
/// 用户主动下线
/// </summary>
/// <param name="voip"></param>
public void LoginOut(string voip)
{ var user = onlineUsers.Where(u => u.Voip == voip).FirstOrDefault();
Console.WriteLine(user.Voip + " 下线了"); onlineUsers.Remove(user); } private void UserLoginOut(string voip)
{
LoginOut(voip);
}
} public class User
{
public string Voip { get; set; }
public int Second { get; set; }
public string ConnectionId { get; set; } private readonly Timer timer;//定时器
/// <summary>
/// 间隔秒数
/// </summary>
private int During=; /// <summary>
/// 掉线后的操作
/// </summary>
public event Action LogoutAction; /// <summary>
/// 发送心跳包的动作
/// </summary>
public event Action HeartBeatAction;
public User() {
Second = ;
if (timer == null) {
timer = new Timer();
}
timer.Start();//计时器启动
timer.Elapsed += (sender, args) =>
{
Second++;
//每5s发送一次心跳包
if (Second % == ) {
if (HeartBeatAction != null) {
HeartBeatAction();
}
}
if (Second >= During) {
timer.Stop();
timer.Dispose();
//用户30s无心跳包应答,则视为掉线,会抛出事件,然后处理用户掉线动作。
if (LogoutAction != null)
{
LogoutAction();
}
}
}; } }
}

上面的代码包括四个类:

Program,包含程序的主方法.在这个方法中,类型为Startup的web应用程序启动于指定的URL (http://localhost:8080). 如果需要更加安全一点,可以支持SSL. 请去这里看看How to: Configure a Port with an SSL Certificate

Startup, 该类含有SignalR服务端的配置(该教程使用的唯一的配置是用来调用UseCors), MapSignalR为所有形式的Hub对象创建了路由规则.

MyHub,  SignalR的Hub 类是程序要提供给客户端的.

User,存储当前登录坐席的信息

js部分:

1. 创建web项目
2. 初始化客户端需要的东西
   Install-Package Microsoft.AspNet.SignalR.JS
3. 创建html页,添加客户端代码:

<!DOCTYPE html>
<html>
<head>
<title>SignalR Simple Chat</title>
<style type="text/css">
.container {
background-color: #99CCFF;
border: thick solid #808080;
padding: 20px;
margin: 20px;
}
</style>
</head>
<body>
<div class="container">
<!--<input type="hidden" id="displayname" />-->
<span>please enter your name:</span> <input type="text" id="displayname" />
<input type="button" id="btnLogin" value="LoginIn" />&nbsp;&nbsp;
<input type="button" id="btnLoginOut" value="LoginOut" /><br /><br />
<input type="text" id="message" />
<input type="button" id="sendmessage" value="Send" /> <ul id="discussion"></ul>
</div>
<!--Script references. -->
<!--Reference the jQuery library. -->
<script src="Scripts/jquery-1.6.4.min.js"></script>
<!--Reference the SignalR library. -->
<script src="Scripts/jquery.signalR-2.2.1.min.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="http://localhost:8080/signalr/hubs"></script>
<!--Add script to update the page and send messages.-->
<script type="text/javascript">
$(function () {
//Set the hubs URL for the connection
$.connection.hub.url = "http://localhost:8080/signalr";
// Declare a proxy to reference the hub.
var chat = $.connection.myHub; // Create a function that the hub can call to broadcast messages.
chat.client.addMessage = function (name, message) {
// Html encode display name and message.
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
// Add the message to the page.
$('#discussion').append('<li><strong>' + encodedName
+ '</strong>:&nbsp;&nbsp;' + encodedMsg + '</li>');
}; chat.client.recieveHeartBeat = function (connId) {
chat.server.recieveHeartBeat(connId);
// chat.server.send(localStorage.LoginvoipAccount, "1");
console.log('***************************** connId:' + connId);
};
// Start the connection.
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
// Call the Send method on the hub.
chat.server.send($('#displayname').val(), $('#message').val());
// Clear text box and reset focus for next comment.
$('#message').val('').focus();
}); $('#btnLogin').click(function () {
chat.server.loginIn($('#displayname').val());
}); $('#btnLoginOut').click(function () {
chat.server.loginOut($('#displayname').val());
})
});
});
</script>
</body>
</html>

参考:http://www.cnblogs.com/humble/p/3856357.html

Signalr 实现心跳包的更多相关文章

  1. 在后台主机中托管SignalR服务并广播心跳包

    什么是后台主机 在之前的 Asp.NETCore 轻松学系列中,曾经介绍过一个轻量级服务主机 IHostedService ,利用 IHostedService 可以轻松的实现一个系统级别的后台服务, ...

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

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

  3. heart beat/心跳包

    为什么需要heart beat/心跳包?因为tcp keep-alive不能满足人们的实时性的要求,就是这么简单. socket的长时间连接的话,是需要心跳包.心跳包就是维持双方的连接,每隔一段时间发 ...

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

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

  5. 为什么心跳包(HeartBeat)是必须的?

    几乎所有的网游服务端都有心跳包(HeartBeat或Ping)的设计,在最近开发手游服务端时,也用到了心跳包.思考思考,心跳包是必须的吗?为什么需要心跳包?TCP没有提供断线检测的方法吗?TCP提供的 ...

  6. TCP之心跳包实现思路

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

  7. socket的心跳包机制

    网络中的接收和发送数据都是使用操作系统中的SOCKET进行实现.但是如果此套接字已经断开,那发送数据和接收数据的时候就一定会有问题.可是如何判断这个套接字是否还可以使用呢?这个就需要在系统中创建心跳机 ...

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

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

  9. UDP打洞和心跳包设计

    一.设备终端class DeviceClient { int deviceID; int IP; int port; char connectID[16]; time_t lastTime; stru ...

随机推荐

  1. IIS 7.5配置PHP站点

    准备工作 首先下载并解压PHP程序文件,比如解压到C:/PHP/,不需要安装.IIS安装略. 第一步:添加ISAPI筛选器和CGI功能 控制面板—>程序和功能—>打开或关闭Windows功 ...

  2. C# 号码归属地查询算法

    C# 号码归属地查询算法(根据Android来电归属地二进制文件查询修改) 前言 近期有个项目需要用到号码归属查询,归属地数据库可能比不上ip138,淘宝上也有卖的-,-! 文本提供一个279188条 ...

  3. Jenkins中关于一些插件的使用

    Jenkins中关于一些插件的使用方法 最近在为公司搭建CI平台过程中,以及在具体项目实施过程中使用过的一些插件的具体用法: 1. ant插件 这个插件可能是我们最为经常使用的,若构建脚本是使用bui ...

  4. socket网络编程快速上手(一)

    工作以来,写了很多socket相关的代码.磕磕碰碰,走了很多弯路,也积累了一些东西,今天正好整理一下.为了证明不是从书上抄来的,逻辑会有点乱(借口,呵呵)!知识点的介绍也不会像书上说的那么详细和精准, ...

  5. OJ题目JAVA与C运行效率对比

    [JAVA]深深跪了,OJ题目JAVA与C运行效率对比(附带清华北大OJ内存计算的对比) 看了园友的评论之后,我也好奇清橙OJ是怎么计算内存占用的.重新测试的情况附在原文后边. ----------- ...

  6. sql 数据库还原脚本 (kill链接+独占

    在开发过程中经常会碰到数据库还原,要是sql 连接没完全释放掉,那么还原就会受到阻碍.此脚本就是为了解决这个问题. USE [master] GO /****** Object: StoredProc ...

  7. lucene 从2.4.0—3.6.0—4.3.1版本升级

    一.从2.4升级到3.6 替换原因:由于使用IBM的jdk导致了查询出现不稳定现象,原因无法找到,只好升级版本,毕竟版本很低 1)替换中文分词器,由原来的MMAnaylze替换为IKAnaylze 2 ...

  8. Android开发之Ubuntu上Eclipse不显示手机设备

    一.准备工作   A.开启Android设备,用USB数据线连接到Ubuntu系统.   B.启用设备的USB调试模试    C.启动Eclipse,在Devices栏会现一个有很多???号的不明设备 ...

  9. 学习ORM框架—hibernate(三):跟踪持久化对象状态,掌握对象持久化

    准备工作 在上篇博客中学习ORM框架—hibernate(一):初识hibernate,通过简单的实例说明O和R的映射过程.本篇博客将要介绍hibernate中持久化对象的状态,并使用hibernat ...

  10. JPA实现分页

    JPA实现分页 Jpa自己已经有了实现分页的基本查询方法,只要自己在网上找一个分页的前端插件,然后再用Jpa查询到数据给它. 页面传当前页和每一页的大小给后台,后台就像下面这样处理: public L ...