前些天写了一篇题为Server-push技术(comet)----------asp.net中的异步处理+client与服务器端的长连接的文章,由于此篇中仅仅讲了一些理论上实现方式,故今天以实例的方式给大家进行一下补充。注:此实例为一个WEB IM模型,文章最后有下载链接。
上篇中讲到了如何让服务器端往客户端以推的方式传输数据,重点就在于客户端与服务器端建立一个长连接,在实际代码中又是什么样的原理呢?
首先说一下客户端从服务器端拉取数据:
1>客户端发送请求到服务器端
2>客户端等待服务器端的响应
3>服务器端将数据返回给客户端(如果服务器端响应慢,你会发现客户端一直处于waiting状态,直到服务器端数据返回)
那再来说说服务器端往客户端推送数据:
1>客户端发送请求到服务器端
2>客户端等待服务器端的响应
3>服务器端将这个客户端请求hold住(此时服务器端要做的就不是将数据返回给客户端,而是让这个客户端一直等着)
4>当服务器端发现有数据时通过hold住的管道将数据返回给客户端
通过上面的两个比较,大家可能会觉得好像差不多,一个是服务器端把数据马上返回给客户端,一个是服务器端需要等一会儿直到服务器端有数据时才把数据返回给客户端,如果用.net中异步回调来理解这个过程就不一样了。
使用.net异步回调来理解server-push,客户端发送的每一个请求都以异步的方式来进行执行,相当于你向服务器端发送了请求,客户端无需等待服务器端的处理完成可以先行完成,服务器端会以异步的方式将数据返回给客户端,这样首先避免了一个问题:HTTP请求的超时问题。其次,客户端对服务器端的每一个请求都被服务器端保存了起来,这个大家可以理解为一个异步线程池,存储了客户端对服务器端的每一次的请求,当服务器端有数据需要返回时,那么首先将会从这个大的异步线程池中找到需要返回给某个客户端数据的HTTP请求,通过这个管道将数据传回到对应的客户端,这样便实现了server-push。
如上图,此实例用到了三个类(注:此三个类为实现server-push的关键之所在)
ServerPush:此类继承IHttpAsyncHandler,定义 HTTP 异步处理程序对象必须实现的协定。
ServerPushResult:此类继承IAsyncResult,表示异步操作的状态。
ServerPushHandler:此类为业务方法类,实现用户登录,信息发送,保持长连接。此类中有一个很关键的静态变量,static Dictionary<string, ServerPushResult>, 用来保存客户端与服务器端的连接。需要往客户端推送数据时都是从此区域选择需要推送的对象。
客户端JS中的wait方法很重要,客户端如果要与服务器端保持一个长连接,那么必须要调用wait方法,wait方法同时也充当于了接头员的作用,当服务器端将数据推送给客户端时,客户端接受数据并显示在页面上是在wait方法中来实现的,当接头员收到讯号这个长连接失效了,如果想继续得到更多的消息,那么接头员必须再发送一个请求给司令部。
function wait() {
$.post("comet_broadcast.asyn", { action: 'connect', uid: $("#txtLoginID").val() },
function (data, status) {
var result = $("#divResult");
result.html(result.html() + "<br/>result:" + data);
wait();
});
}
这个是我给大家提供的实例下载地址,例子很简单,前提条件是必须要对.net中的异步回调很清晰,server-push已经得到越来越多的应用,我们可以用在一些实时性很强的场合,这样可以减少服务器端的压力,但是会增加WEB服务器的连接数,不过我们可以在程序上进行一些相应的控制,譬如当客户端多久没有进行响应我们自动将其过期,仅保留一些有效的连接,减少WEB服务器连接数。
ps:示例用的是IIS7,所以如果用的是IIS7以下的版本,自己需要在web.config中的httphandlers节中配置:
<add verb="*" path="comet_broadcast.asyn" type="lucky.zeng.ServerPush"/>