我个人的理解是,看起来就像在Web环境中客户端能订阅服务端的事件,服务器端通过事件去通知客户端。如果服务器端用 ASP.NET 来实现,可以利用 .NET 的事件驱动机制,很有意思,下面的示例代码将展示这一点。
先看Web前端js代码:
代码如下 | 复制代码 |
jQuery(function ($) { function long_polling() { $.getJSON('/comet/LongPolling', function (data) { if (data.d) { $('#logs').append(data.d + "<br/>"); } long_polling(); }); } long_polling(); }); |
js代码很简单,就是一个递归调用(调用在callback时进行的),通过jQuery的$.getJSON发起Ajax请求,'/comet/LongPolling' 表示请求的服务端 CometController 的 LongPolling Action 的网址。这里我们可以看出实现 Comet 的难点不在 Web 前端,而是在服务器端。
接下来重点看 Web 服务器 ASP.NET MVC Controller 的代码。
首先要注意的是为了响应 XMLHttpRequest long polling 请求,我们需要实现一个异步控制器(AsyncController),如果您对 AsyncController 不熟悉,建议阅读MSDN上的文章 Using an Asynchronous Controller in ASP.NET MVC 。
先上 Controller 的实现代码:
(注:该控制器实现的功能是每隔5秒钟向客户端发送服务器当时间)
代码如下 | 复制代码 |
public class CometController : AsyncController { //LongPolling Action 1 - 处理客户端发起的请求 public void LongPollingAsync() { //计时器,5秒种触发一次Elapsed事件 System.Timers.Timer timer = new System.Timers.Timer(5000); //告诉ASP.NET接下来将进行一个异步操作 AsyncManager.OutstandingOperations.Increment(); //订阅计时器的Elapsed事件 timer.Elapsed += (sender, e) => { //保存将要传递给LongPollingCompleted的参数 AsyncManager.Parameters["now"] = e.SignalTime; //告诉ASP.NET异步操作已完成,进行LongPollingCompleted方法的调用 AsyncManager.OutstandingOperations.Decrement(); }; //启动计时器 timer.Start(); } //LongPolling Action 2 - 异步处理完成,向客户端发送响应 |
实现异步控制器需要继承 System.Web.Mvc.AsyncController,并将 Action 分解为两个,比如 Action 叫 LongPolling,则分解为 LongPollingAsync 与 LongPollingCompleted 。LongPollingAsync 接受客户端请求,并发起异步操作;异步操作完成,调用LongPollingCompleted。
AsyncManager.OutstandingOperations.Increment(); 告诉ASP.NET接下来将进行一个异步操作。
AsyncManager.OutstandingOperations.Decrement(); 告诉ASP.NET异步操作完成,请调用LongPollingCompleted()方法。
示例代码中的异步操作就是将服务器当前时间作为参数传递给 LongPollingCompleted() 方法,LongPollingCompleted() 获取服务器当前时间并传递给客户端,客户端收到后将之显示出来,将继续发起 Ajax 请求 ... 这样周而复始,实现了基于 XMLHttpRequest long polling 的 Comet。