asp.net 中长尾链接实现推送 -- comet
一般需求推送服务时,都会去第三方拿推送组件,如”极光“,”百度“,”小米"什么的,自己用.net实现推送服务端需要面对很多问题,比如C10K,但是企业内部使用往往用不了10K的链接,有个1K,2K就足够,这个时候完全可以自己实现一个推送服务,这样手机应用就不用走外网了。
使用.net实现推送服务有几个选择
1.是使用WCF 基于TCP的回调-针对.net To .net 端,经过7*24小时测试,2K左右的链接能稳定hold住,参考:http://www.cnblogs.com/wdfrog/p/3924718.html
2.自己使用TcpListener或Socket实现一个长连击服务器,由于推送的信息都很短(长信息只推送信息编号),这样在一个MTU里面就可以完成传输,整体上实现起来也不麻烦 ,最近也做了个,大概加一起就400百来行代码,2K链接已经(实际只要hold住98个用户就好了)稳定运行了6天了。
3.使用Comet Request, 首先Comet Request 采用Asp.net + IIS,整整网页就好了,另外由于IIS应用程序池会定期回收,程序写的烂点也不影响,每天都给你一个新的开始,还有Comet 的实现网上代码很多,还有开源的SignalR可以用.
采用Comet方式的实现
1.服务端,使用IHttpAsyncHandler来Hold住请求,需要根据cookie或QueryString中带的UserId来区分不同的用户
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace MangoPush.WebComet.Core
{
public class PushAsyncHandle : IHttpAsyncHandler
{
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{ var ar = new PushAsyncResult(context, cb, extraData);
CometRequestMgr.Instance.Add(ar);
return ar;
} public void EndProcessRequest(IAsyncResult result)
{ } public bool IsReusable
{
get { return true; }
} public void ProcessRequest(HttpContext context)
{
throw new NotImplementedException();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading; namespace MangoPush.WebComet.Core
{
public class PushAsyncResult:IAsyncResult
{
private static int GId = ; private bool m_IsCompleted = false;
private AsyncCallback Callback = null;
public HttpContext Context;
private Object _AsyncState;
public DateTime AddTime{get;private set;}
public int Id { get; set; } public PushAsyncResult(HttpContext context, AsyncCallback callback, object asyncState)
{
Context = context;
Callback = callback;
_AsyncState = asyncState;
AddTime = DateTime.Now;
Interlocked.Increment(ref GId);
int userId = int.TryParse(Context.Request["UserId"], out userId) ? userId : ;
Id = userId;
if (userId == )
{
Release(JUtil.ToJson(new {Code=-,Msg="未提供UserId" }));
}
}
public void Release(string msg)
{
try
{
try
{
Context.Response.Write(msg);
}
catch { }
if (Callback != null)
{
Callback(this);
}
}
catch { }
finally
{
m_IsCompleted = true;
}
}
public object AsyncState
{
get { return _AsyncState; }
} public System.Threading.WaitHandle AsyncWaitHandle
{
get { return null; }
} public bool CompletedSynchronously
{
get { return false; }
} public bool IsCompleted
{
get { return m_IsCompleted; }
}
}
}
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Web; namespace MangoPush.WebComet.Core
{
public class CometRequestMgr
{ public static readonly CometRequestMgr Instance = new CometRequestMgr();
private ConcurrentDictionary<int, PushAsyncResult> Queue = new ConcurrentDictionary<int, PushAsyncResult>(); private CometRequestMgr()
{
var timer = new System.Timers.Timer();
timer.Interval = * ;
timer.AutoReset = false;
timer.Elapsed += (s, e) =>
{ try
{ var list = Queue.Select(ent => ent.Value).ToList();
#region 清理完成链接
foreach (var it in list)
{
if (it.IsCompleted)
{
try
{
PushAsyncResult c = null;
Queue.TryRemove(it.Id,out c); }
catch (Exception ex)
{ continue;
}
}
}
#endregion }
catch (Exception ex)
{ }
finally
{
timer.Start();
} };
timer.Start(); } public void Add(PushAsyncResult ar)
{
Queue[ar.Id] = ar;
}
public void BroadCastMsg(string msg)
{
msg +="," + DateTime.Now.ToString();
foreach (var c in Queue)
{
try
{ c.Value.Release(JUtil.ToJson( new {Code=,Msg= msg})); }
catch { }
finally
{
PushAsyncResult outIt=null;
Queue.TryRemove(c.Key,out outIt);
}
}
}
}
}
2.网页端,使用ajax方式发起访问,特别注意的是需要设置timeout,这样如果断线或者服务端挂了重启,可以自动修复
$(function () {
function long_polling() {
var _url = '/pushService.act?userId=' + $("#userId").val();
console.log(_url);
var ajaxRequest = $.ajax({
url: _url, //请求的URL
timeout: 1000 * 60 * 3, //超时时间设置,单位毫秒
type: 'get', //请求方式,get或post
data: {}, //请求所传参数,json格式
dataType: 'json', //返回的数据格式
success: function (data) { //请求成功的回调函数
console.log(data);
if (data.Code == 0) {
$('#msg').append(data.Msg + "<br/>");
}
},
complete: function (XMLHttpRequest, status) { //请求完成后最终执行参数
if (status == 'timeout') {//超时,status还有success,error等值的情况
ajaxRequest.abort();
console.log("超时");
}
if ($("#btn").val() == "停止") {
long_polling();
}
}
});
}
$("#btn").click(function () {
if ($("#btn").val() == "启动") {
long_polling();
$("#btn").val("停止");
} else {
$("#btn").val("启动");
}
});
$("#btnCls").click(function () {
$("#msg").text("");
});
});
3.Winform端,采用WebClient发起请求,并且使用AutoResetEvent控制超时重连(相当于心跳包)
private void Do()
{
try
{ while (Enable)
{
Console.WriteLine("发起请求!");
var url = @"http://192.168.9.6:9866/pushService.act?userId=18";
using (var wc = new WebClient())
{
wc.Encoding = Encoding.UTF8;
#region 回调处理
wc.DownloadStringCompleted += (s, e) => { if (e.Error != null)
{
Console.WriteLine(e.Error);
}
else if (e.Cancelled)
{
Console.WriteLine("Be Cancelled!");
}
else
{
Console.WriteLine(e.Result); }
autoReset.Set();
};
#endregion
var uri = new Uri(url);
wc.DownloadStringAsync(uri); var isOK= autoReset.WaitOne(1000 * 60 * 5);
if (!isOK)
{
wc.CancelAsync();
} }
}
}
catch (Exception ex)
{
Console.WriteLine("错误" + ex.Message);
}
finally
{
if (Enable)
{
ThreadPool.QueueUserWorkItem(o => { Do(); }, null);
}
} }
4.Android端
1.类似WinForm端,目前采用AsyncHttpClient,写法跟Js差不多,需要设置timeout
2.由于android会回收进程,需要AlarmManager,定期检查推送服务是否还存活
3.android系统重启,开关网络,调整时间,需要订阅相应广播,调整AlermManager,触发平率。
总结:
整个能支持10K,100K,2000K链接的,挺不容易,但是一般中小企业使用1K,2K甚至0.1K足矣,3,4百行代码就完事,至少可以让员工不用连3G,4G了,NND,提速降价,也不知道降那去了。
最后整2个图片


asp.net 中长尾链接实现推送 -- comet的更多相关文章
- 在 Asp.NET MVC 中使用 SignalR 实现推送功能 [转]
在 Asp.NET MVC 中使用 SignalR 实现推送功能 罗朝辉 ( http://blog.csdn.net/kesalin ) CC许可,转载请注明出处 一,简介 Signal 是微软支持 ...
- MVC 中使用 SignalR 实现推送功能
MVC 中使用 SignalR 实现推送功能 一,简介 Signal 是微软支持的一个运行在 Dot NET 平台上的 html websocket 框架.它出现的主要目的是实现服务器主动推送(Pus ...
- Asp.NET MVC 使用 SignalR 实现推送功能二(Hubs 在线聊天室 获取保存用户信息)
简单介绍 关于SignalR的简单实用 请参考 Asp.NET MVC 使用 SignalR 实现推送功能一(Hubs 在线聊天室) 在上一篇中,我们只是介绍了简单的消息推送,今天我们来修改一下,实现 ...
- AngularJS+ASP.NET MVC+SignalR实现消息推送
原文:AngularJS+ASP.NET MVC+SignalR实现消息推送 背景 OA管理系统中,员工提交申请单,消息实时通知到相关人员及时进行审批,审批之后将结果推送给用户. 技术选择 最开始发现 ...
- IOS中程序如何进行推送消息(本地推送,远程推送)
[1]-------------什么是推送消息? 我就以一张图解释------------ [2]-----------IOS程序中如何进行本地推送?----------- 2.1,先征求用户同意 1 ...
- JAVA使用百度链接实时推送API提交链接
官网地址:http://data.zz.baidu.com/ 百度推广API的token获取 http://data.zz.baidu.com/site/index 填写完之后会进行验证, 验证完之后 ...
- Asp.NET MVC 中使用 SignalR 实现推送功能
一,简介Signal 是微软支持的一个运行在 Dot NET 平台上的 html websocket 框架.它出现的主要目的是实现服务器主动推送(Push)消息到客户端页面,这样客户端就不必重新发送请 ...
- 在 Asp.NET MVC 中使用 SignalR 实现推送功能
一,简介Signal 是微软支持的一个运行在 Dot NET 平台上的 html websocket 框架.它出现的主要目的是实现服务器主动推送(Push)消息到客户端页面,这样客户端就不必重新发送请 ...
- ASP.NET MVC SignalR 简单聊天推送笔记
介绍:(抄袭于网络) ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指这样一种功能:当所连接 ...
随机推荐
- UI5-文档-4.32-Routing with Parameters
现在我们可以在overview和detail页面之间导航,但是我们在overview中选择的实际项目还没有显示在detail页面上.我们的应用程序的一个典型用例是在详细信息页面上显示所选项目的附加信息 ...
- ArcGIS模型构建器案例学习笔记-字段处理模型集
ArcGIS模型构建器案例学习笔记-字段处理模型集 联系方式:谢老师,135-4855-4328,xiexiaokui@qq.com 由四个子模型组成 子模型1:判断字段是否存在 方法:python工 ...
- CSS3 弹性盒模型 box-flex
说明:本文档兼容性测试基础环境为:windows系统:IE6-IE10, Firefox6.0, Chrome13.0, Safari5.1, Opera11.51 语法: box-flex:< ...
- 【Linux】svn环境配置
Ubuntu 安装svn环境配置 1. 安装 sudo apt-get install subversion 安装过程需要数据[Y] 2. svn位置选择 安装完成之后,选择svn目录位置, 将其放在 ...
- docker 操作
docker daemon 设置代理 http_proxy=109.105.4.17:8118 & systemctl start docker centos: Edit /etc/sysco ...
- Spring Retry
最近组内准备将项目中原有的重试功能抽取出来重构为一个重试平台,由于对重试的功能要求比较高,采用了不少中间件和框架(jimdb,jproxy, Elastic-Job ,JMQ,Hbase, Disru ...
- Linux终极渗透测试命令总结
本文主要和大家分享Linux终极渗透测试命令总结,如下是一份 Linux 机器的渗透测试备忘录,是在后期开发期间或者执行命令注入等操作时的一些典型命令,设计为测试人员进行本地枚举检查之用. 命令 描述 ...
- getchar()、putchar()、gets()、puts()、cin.get()、cin.getline()、getline()
1.getchar: 原型为int getchar(void). 它从stdin里读取一个字符.返回值为用户输入的ASCⅡ码,出错返回-1. eg:c=getchar(). 2.putchar: 原型 ...
- C++重载、重写(覆盖)、隐藏
类成员函数中重载/重写(覆盖)/重定义(隐藏)的区别? 答:分别简单讲述一下函数重载,函数覆盖,函数隐藏的概念与特征: 函数重载:重载函数通常用来命名一组功能相似的函数 1.函数要在相同的类域 2.函 ...
- centos7下编译安装php-7.0.15(PHP-FPM)
centos7下编译安装php-7.0.15(PHP-FPM) 一.下载php7源码包 http://php.net/downloads.php 如:php-7.0.15.tar.gz 二.安装所需依 ...