1.消息类,可直接通过这个类推送消息 HttpMessages using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; namespace Holworth.Utility { public class HttpMessages { //记录所有请求的客户端 List<WebAsynResult> clients = new List<WebAsynResult>(); #region 实现该类的单例 private static readonly HttpMessages _Instance = new HttpMessages(); private HttpMessages() { } public static HttpMessages Instance() { return _Instance; } #endregion public void AddMessage(string content, WebAsynResult asyncResult) { //当传入的内容为"-1"时,表示为建立连接请求,即为了维持一个从客户端到服务器的连接而建立的连接 //此时将该连接保存到 List<myAsynResult> clients中,待再有消息发送过来时,该连接将会被遍历,并且会将该连接输出内容后,结束该连接 if (content == "-1") { clients.Add(asyncResult); } else { //将当前请求的内容输出到客户端 asyncResult.Content = content; asyncResult.Send(null); //否则将遍历所有已缓存的client,并将当前内容输出到客户端 foreach (WebAsynResult result in clients) { result.Content = content; result.Send(null); } //清空所有缓存 clients.Clear(); } } } } 2.异步请求接口WebAsnyHandler实现类 using System; using System.Collections.Generic; using System.Web; using System.Threading; namespace Holworth.Utility { /// <summary> /// Summary description for AsnyHandler /// </summary> public class WebAsnyHandler : IHttpAsyncHandler { public WebAsnyHandler() { } public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { //myAsynResult为实现了IAsyncResult接口的类,当不调用cb的回调函数时,该请求不会返回到给客户端,会一直处于连接状态 WebAsynResult asyncResult = new WebAsynResult(context, cb, extraData); String content = context.Request.Params["content"]; //向Message类中添加该消息 HttpMessages.Instance().AddMessage(content, asyncResult); return asyncResult; } #region 不必理会 public void EndProcessRequest(IAsyncResult result) { } public bool IsReusable { get { return false; ; } } public void ProcessRequest(HttpContext context) { } #endregion } } 3.异步请求结果类WebAsynResult using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; namespace Holworth.Utility { public class WebAsynResult : IAsyncResult { bool _IsCompleted = false; private HttpContext context; private AsyncCallback cb; private object extraData; public WebAsynResult(HttpContext context, AsyncCallback cb, object extraData) { this.context = context; this.cb = cb; this.extraData = extraData; } private string _content; public string Content { get { return _content; } set { _content = value; } } #region IAsyncResult接口 public object AsyncState { get { return null; } } public System.Threading.WaitHandle AsyncWaitHandle { get { return null; } } public bool CompletedSynchronously { get { return false; } } public bool IsCompleted { get { return _IsCompleted; } } #endregion //在Message类中的添加消息方法中,调用该方法,将消息输入到客户端,从而实现广播的功能 public void Send(object data) { context.Response.Write(this.Content); if (cb != null) { cb(this); } _IsCompleted = true; ; } } } 4.客户端 请求分两步 发送数据send和等待数据的请求,若有数据则响应继续进入等待数据的状态,若无数据进入等待状态,异步接口缓存客户端的异步请求结果 js部分 /// <reference path="jquery-1.3.2.min.js" > function send(content) { // alert("step=" + $("#content").val()); //var content = getUrlParam("step"); //向comet_broadcast.asyn发送请求,消息体为文本框content中的内容,请求接收类为WebAsnyHandler $.post("comet_broadcast.asyn", { content: content }); //清空内容 $("#content").val(""); } function getUrlParam(pName, win) { var sUrl; if (typeof (win) == 'string') { sUrl = win; if (sUrl.indexOf('?') < 0) sUrl = '?' + sUrl; } else { if (!win) win = window; sUrl = win.location.search; } var iQ = sUrl.indexOf('?') + 1; if (iQ > 0) { sUrl = '&' + sUrl.substring(iQ, sUrl.length); iQ = sUrl.indexOf('?'); //url参数中还存在url? var key = '&' + pName + '='; var i = sUrl.indexOf(key); if (i > -1) { var j = sUrl.indexOf('&', i + 1); //&Key=Val&Key2=... if (j < 0 || (iQ > 1 && j > iQ)) j = sUrl.length; return unescape(sUrl.substring(i + key.length, j)); } } return null; }; //未找到服务响应的客户端进入等待状态,待服务端响应之后,再次等待,一直循环 function wait() { // alert("初始化前") $.post("comet_broadcast.asyn", { content: "-1" }, function (data, status) { var result = $("#divResult"); result.html(result.html() + "<br/>" + data); // alert("初始化后") //服务器返回消息,再次立连接 wait(); }, "html" ); } $(function () { //初始化连接 wait(); //测试代码 $("#btnSend").click(function () { send($("#content").val()); }); $("#content").keypress(function (event) { if (event.keyCode === 13) { send($("#content").val()); } }); }); 5。这里在另一个页面进行数据的推送,不过是service还是页面都可以 LongConnectServer.aspx,前台部分无关紧要,直接看后台调用 using Holworth.Utility; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace Comet_by_ASP.NET { public partial class LongConnectServer : System.Web.UI.Page { public void aa() { for (int i = 0; i < 1000; i++) { } } public void bb() { WebAsynResult asyncResult = new WebAsynResult(HttpContext.Current, null,null); HttpMessages.Instance().AddMessage("1", asyncResult); Thread.Sleep(1000); HttpMessages.Instance().AddMessage("2", asyncResult); Thread.Sleep(1000); HttpMessages.Instance().AddMessage("3", asyncResult); Thread.Sleep(1000); HttpMessages.Instance().AddMessage("4", asyncResult); Thread.Sleep(1000); HttpMessages.Instance().AddMessage("5", asyncResult); Thread.Sleep(1000); HttpMessages.Instance().AddMessage("6", asyncResult); //WebRequestUtility req = new WebRequestUtility(); //var para = new Dictionary<string, string>(); //para.Add("_method", "compute"); //para.Add("step", "1"); //req.HttpGet("http://localhost:12688/Default2.aspx", para); //return; //para.Clear(); //// //para.Add("_method", "compute"); //para.Add("step", "2"); //req.HttpGet("http://localhost:12688/Default2.aspx", para); //return; //// //para.Clear(); //para.Add("_method", "compute"); //para.Add("step", "3"); //req.HttpGet("http://localhost:12688/Default2.aspx", para); //// //para.Clear(); //para.Add("_method", "compute"); //para.Add("step", "4"); //req.HttpGet("http://localhost:12688/Default2.aspx", para); //// //para.Clear(); //para.Add("_method", "compute"); //para.Add("step", "5"); //req.HttpGet("http://localhost:12688/Default2.aspx", para); //// //para.Clear(); //para.Add("_method", "compute"); //para.Add("step", "6"); //req.HttpGet("http://localhost:12688/Default2.aspx", para); } protected void Page_Load(object sender, EventArgs e) { bb(); } } } 6.长连接客户端 LongConnectClinet 6.1 html <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="LongConnectClient.aspx.cs" Inherits="Comet_by_ASP.NET.LongConnectClient" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> <style type="text/css"> *{ font-size:12px;} #divResult { border:1px solid #000; 250px; } </style> <script src="/Scripts/jquery.min.1.11.3.js"></script> <script src="/Scripts/WebAsync.js"></script> </head> <body> <form runat="server" id="form1"> 广播内容: <input type="text" id="content" /><br /> 消息记录: <div id="divResult"></div> <input type="button" id="btnSend" value="广播" /> </form> </body> </html> 6.2 后台代码 这里的代码无关紧要 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace Comet_by_ASP.NET { public partial class LongConnectClient : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { //switch (Request["_method"]) //{ // case "compute": // Page.ClientScript.RegisterClientScriptBlock(this.GetType(), Guid.NewGuid().ToString(), "<script>wait();send();</script>"); // break; //} } } } 7.web.config <system.webServer> <modules runAllManagedModulesForAllRequests="true"> <remove name="FormsAuthentication" /> <remove name="ApplicationInsightsWebTracking" /> <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" preCondition="managedHandler" /> </modules> <handlers> <add name="comet_broadcast" path="comet_broadcast.asyn" type="Handle.WebAsnyHandler" verb="POST,GET"/> </handlers> <validation validateIntegratedModeConfiguration="false" /> </system.webServer>