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 功能是指这样一种功能:当所连接 ...
随机推荐
- Yii2 基础学习
<?php //url创建 echo Url::to(''); // same controller, different action // /index.php?r=management/d ...
- 在 WampServer 上手工安装 PHP 的多个版本
手工安装新版本的PHP,只需以下步骤: 下载要安装的PHP版本.既然是用WampServer,那当然是下载Window版本的ZIP包啦:http://windows.php.net.解压到 Wamp的 ...
- 修改thinkpad 小红点(TrackPoint速度)
from: http://www.jianshu.com/p/b9677e9e56ec Thinkpad大概是对Linux支持最好的笔记本了,Ubuntu大概是对硬件支持最好的Linux发行版了.Ub ...
- Java常见的乱码解决方式
JAVA几种常见的编码格式(转) 简介 编码问题一直困扰着开发人员,尤其在 Java 中更加明显,因为 Java 是跨平台语言,不同平台之间编码之间的切换较多.本文将向你详细介绍 Java 中编码 ...
- 吴裕雄 实战PYTHON编程(9)
import cv2 cv2.namedWindow("ShowImage1")cv2.namedWindow("ShowImage2")image1 = cv ...
- python网络编程——socket基础篇
python的网络编程比c语言简单许多, 封装许多底层的实现细节, 方便程序员使用的同时, 也使程序员比较难了解一些底层的东西. 1 TCP/IP 要想理解socket,首先得熟悉一下TCP/IP协议 ...
- js:Date格式化
将Date类型格式化为"yyyy/MM/dd HH:mm:ss" 函数代码如下: //Date的prototype 属性可以向对象添加属性和方法. Date.prototype.F ...
- 早上突然看明白 shader和材质球的关系
计算机的世界不外乎 指令+数据 shader即Gpu指令,材质即数据
- jQuery html5Validate基于HTML5表单验证插件
更新于2016-02-25 前面提到的新版目前线上已经可以访问: http://mp.gtimg.cn/old_mp/assets/js/common/ui/Validate.js demo体验狠狠地 ...
- swift - 代码创建 pickerView 显示或隐藏横线
import UIKit class VC1: UIViewController { fileprivate lazy var pickerV : UIPickerView = { let v = U ...