一般需求推送服务时,都会去第三方拿推送组件,如”极光“,”百度“,”小米"什么的,自己用.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的更多相关文章

  1. 在 Asp.NET MVC 中使用 SignalR 实现推送功能 [转]

    在 Asp.NET MVC 中使用 SignalR 实现推送功能 罗朝辉 ( http://blog.csdn.net/kesalin ) CC许可,转载请注明出处 一,简介 Signal 是微软支持 ...

  2. MVC 中使用 SignalR 实现推送功能

    MVC 中使用 SignalR 实现推送功能 一,简介 Signal 是微软支持的一个运行在 Dot NET 平台上的 html websocket 框架.它出现的主要目的是实现服务器主动推送(Pus ...

  3. Asp.NET MVC 使用 SignalR 实现推送功能二(Hubs 在线聊天室 获取保存用户信息)

    简单介绍 关于SignalR的简单实用 请参考 Asp.NET MVC 使用 SignalR 实现推送功能一(Hubs 在线聊天室) 在上一篇中,我们只是介绍了简单的消息推送,今天我们来修改一下,实现 ...

  4. AngularJS+ASP.NET MVC+SignalR实现消息推送

    原文:AngularJS+ASP.NET MVC+SignalR实现消息推送 背景 OA管理系统中,员工提交申请单,消息实时通知到相关人员及时进行审批,审批之后将结果推送给用户. 技术选择 最开始发现 ...

  5. IOS中程序如何进行推送消息(本地推送,远程推送)

    [1]-------------什么是推送消息? 我就以一张图解释------------ [2]-----------IOS程序中如何进行本地推送?----------- 2.1,先征求用户同意 1 ...

  6. JAVA使用百度链接实时推送API提交链接

    官网地址:http://data.zz.baidu.com/ 百度推广API的token获取 http://data.zz.baidu.com/site/index 填写完之后会进行验证, 验证完之后 ...

  7. Asp.NET MVC 中使用 SignalR 实现推送功能

    一,简介Signal 是微软支持的一个运行在 Dot NET 平台上的 html websocket 框架.它出现的主要目的是实现服务器主动推送(Push)消息到客户端页面,这样客户端就不必重新发送请 ...

  8. 在 Asp.NET MVC 中使用 SignalR 实现推送功能

    一,简介Signal 是微软支持的一个运行在 Dot NET 平台上的 html websocket 框架.它出现的主要目的是实现服务器主动推送(Push)消息到客户端页面,这样客户端就不必重新发送请 ...

  9. ASP.NET MVC SignalR 简单聊天推送笔记

    介绍:(抄袭于网络) ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指这样一种功能:当所连接 ...

随机推荐

  1. sql 数据库修复

    数据库修复 exec sp_dboption 'dbname1','single user',‘true’ dbcc checkdb('dbname1') dbcc checkdb('dbname1' ...

  2. iphone splash screen

    https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articl ...

  3. unity 加载读取外部XML

    cfg.xml <rootNode> <category name="网站"> <item name="mainPage"> ...

  4. 迷你MVVM框架 avalonjs 学习教程20、路由系统

    SPA的成功离开不这三个东西,分层架构,路由系统,储存系统.分层架构是我们组织复杂代码的关键,这里特指MVVM的avalon:路由系统是将多个页面压缩在一个页面的关键:储存系统特指本地储存,是安全保存 ...

  5. godaddy nginx https 配置

    一. 生成秘钥key,运行: $ openssl genrsa -des3 -out server.key 2048 1 会有两次要求输入密码,输入同一个即可 输入密码 然后你就获得了一个server ...

  6. php 利用迭代器遍历文件夹

    1.遍历文件夹 scandir 2.原生的迭代器Iterrate $scan_dir = "txtDir"; //下面会遍历txtDir 下面所有字文件夹中的文件哦 $dir_it ...

  7. Electron Browser加载iframe(webview src属性)

    browser或者webcontents 的高度与宽度比例对webview中src的页面结构也是有一定影响的

  8. Java8 Map的遍历方式

    在这篇文章中,我将对Map的遍历方式做一个对比和总结,将分别从JAVA8之前和JAVA8做一个遍历方式的对比,亲测可行. public class LambdaMap { private Map< ...

  9. EasyUI查询

    <script type="text/javascript"> <!-- js --> function search_xxx() { var search ...

  10. 在winsshd 中添加id_rsa.pub 实现Windows 服务器主机自动信任Linux 客户端

    文章一. 生成密钥: 在Linux主机(ssh客户端),通过ssh-keygen在建立SSH keys# ssh-keygen -t rsa (连续三次回车,即在本地生成了公钥和私钥,不设置密码)将在 ...