HTML5服务器推送消息的各类解决办法

 

摘要

在各类BS架构的应用程序中,每每都但愿服务端可以主动地向客户端推送各类消息,以达到相似于邮件、消息、待办事项等通知。html

往BS架构自己存在的问题就是,服务器一直采用的是一问一答的机制。这就意味着若是客户端不主动地向服务器发送消息,服务器就没法得知如何给客户端推送消息。ajax

随着HTML、浏览器等各项技术、标准的发展,依次生成了不一样的手段与方法可以实现服务端主动推送消息,它们分别是:AJAX,Comet,ServerSent以及WebSocket。算法

本篇文章将对上述说起到的各类技术手段进行直白化的解释。编程


AJAX

正常的一个页面在浏览器中是这样工做的:浏览器

  1. 用户向给予浏览器一个须要访问的地址
  2. 浏览器根据这个地址访问服务器,并与服务器之间建立一个TCP链接(HTTP请求)
  3. 服务器根据这个地址和一些其它数据,组建一段HTML文本,将写入TCP链接,而后关闭链接
  4. 浏览器获得了来自服务器的HTML文本,解析并呈现了浏览器上给用户浏览

此时,用户点击了网站上任何一个<a>或触发任何一个<form>提交时:服务器

  1. 浏览器根据form的参数或者a的参数,做为访问的地址
  2. 与服务器建立TCP链接
  3. 服务器组建HTML文本,而后关闭链接
  4. 浏览器将当前显示的页面摧毁,并按照新的HTML文本呈现一个新的页面给用户

咱们不难发现的是整个过程当中间,一旦创建了一个链接,页面就没法再维护住了。整个过程看上去有点强买强卖,也许我只要一杯新的可乐,但你非要给我一整个套餐组合。架构

此时咱们能够了解一下XmlHttpRequest组件,这个组件提供咱们手动建立一个HTTP请求,发送咱们想要的数据,服务器也能够只返回咱们想要的结果,最大的好处是,当咱们收到服务器的响应时,原来的页面没有被摧毁。这就比如,我喊一句"个人咖啡喝完了,我要续杯",而后服务员就拿了一杯咖啡过来,而不是会把我没吃完的套餐所有倒掉。框架

当咱们利用AJAX实现服务器推送时,其实质是客户端不停地向服务器询问"有没有给个人消息呀?",而后服务器回答"有"或"没有"来达到的实现效果。它的实现方法也很简单,利用jQuery框架封装好的AJAX调用也很方便:函数

function getMessage(fn) {
    $.ajax({
        url: "Handler.ashx", //一个可以提供消息的页面
        dataType: "text",    //响应类型,能够是JSON,XML等其它类型
        type: "get",         //HTTP请求类型,还能够是post
        success: function (d, s) {
            fn(d);           //获得了正常的响应时,利用回调函数通知外部
        },
        complete: function (x, s) {
            setTimeout(function () {
                getMessage(fn);
            }, 5000);       //不管响应成功或失败,在若干秒后再询问一次服务器
        }
    });
}

 经过上面的代码,能够每隔5秒询问一次服务器是否有须要处理的消息,经过这种方式能够达到推送的效果,可是会存在一个问题:post

  1. 间隔时间越快,推送的及时性越好,服务器的消费越大;
  2. 间隔时间越慢,推送的及时性越低,服务器的消费越小。

并且严格地来讲,这种实际方式,并非真正意义上的服务器主动推送消息,但因为早期技术手段缺少,因此AJAX轮循成为了一种很广泛的手段。

 


 

 

Comet

咱们知道HTTP请求实际上是基于TCP链接实现的,再看看以前说的HTTP请求处理过程:

  1. 客户端与服务器创建TCP链接
  2. 服务器根据客户端提交的报文处理并生成HTML文本
  3. 将HTML封闭成为HTTP协议报文并返回给客户端
  4. 关闭连接。

看到这个处理过程,咱们不难联想到,若是把第4步——关闭链接给省掉,那不就至关于有一个长链接一直被维持住了么。经过对服务端的一些操做,咱们能够直接将数据从这个TCP链接发送客户端了。

经过这种技术,咱们能够大大提升服务器推送的实时性,还能够减去服务端不停地创建、施放链接所造成的开销。

目前市面上有很多基于AJAX实现的Comet机制,但主要有两种方式:

  1. 创建链接后依然使用"询问"+"应答"的模式。虽然工做方式没变,可是由于减去了每次创建与施放链接的工做,因此性能上提高了不少。并且服务器对TCP链接能够有上下文的定义,而不像之前的AJAX彻底是无状态的。
  2. 经过对Stream的写入实现服务器将数据主动发送到客户端。由于是TCP链接,因此经过对服务器的编程,咱们能够主动的把数据从服务端发送给客户端,从模式上真正创建起了推送的概念。

 


 

 

Server-Sent

Server-Sent是HTML5提出一个标准,它延用了Comet的思路,并对其进行了一些规范。使得Comet这项技术由原来的分支衍生技术转成了正统的官方标准。

它的原理与Comet相同,由客户端发起与服务器之间建立TCP链接,而后并维持这个链接,至到客户端或服务器中的作任何一放断开,ServerSent使用的是"问"+"答"的机制,链接建立后浏览器会周期性地发送消息至服务器询问,是否有本身的消息。

这项标准不只要求了支持的浏览器可以原生态的建立与服务器的长链接,更要求了对JavaScript脚本的统一性,使得兼程该功能的浏览器可使用同一套代码完成Server-Sent的编码工做。

建立代码很是简单:

//定义一个ServerSent对象
var s = new EventSource("Handler.ashx");
//当收到一个非自定义事件时的回调函数
s.onmessage = function (e) {
    alert(e.data);
};
//当收到一个被服务器命名为MyEvent事件消息时的回调函数
s.addEventListener("MyEvent", function (e) {
    alert(e.data);
});

而服务器的代码也很简单:

public class Handler : IHttpHandler
{

    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/event-stream";
        context.Response.Expires = -1;
        context.Response.Write("event: MyEvent\r\n");       //事件类型,使用\r\n结尾
        context.Response.Write("data: HelloWorld!\r\n");    //事件数据,换行时使用\r\n,并在新行再加上data:
        context.Response.Write("data: I'm server!\n\n");    //事件数据结束,使用\n\n
        context.Response.Flush();                           //这里不能用End,不然是关闭链接的
    }

    public bool IsReusable
    {
        get
        {
            return true;
        }
    }

}

两小段代码,就已经具有了服务器消息推送了。

总得来讲SeverSent就是HTML5规范下的Comet,具备更好的统一性,并且简单好用。

 

 


 

 

WebSocket

看名字就知道了,这是一个能够用在浏览器上的Socket链接。

这也是一个HTML5标准中的一项内容,他要求浏览器能够经过JavaScript脚本手动建立一个TCP链接与服务端进行通信。

WebSocket不包含太多的额外功能,仅仅就是TCP链接的几项基本功能:创建,临时以及发送。

另外WebSocket使用了ws和wss协议,须要服务器有与之握手的算法才能将链接打开。

因此WebSocket相对于以前几种手段来讲,其编码量是最大的,但因为没有其它的约束,所以它也能够自由地实现全部可能的功能。

便可以知足"问"+"答"的响应机制,也能够实现主动推送的功能。

与ServerSent相同,HTML5也对WebSocket调用的JavaScript进行规范,咱们能够弄过很简单的一代码构建一个WebSocket链接

var ws = new WebSocket("ws://192.168.0.105:10080"); //链接服务器        

ws.onopen = function (event) { alert("已经与服务器创建了链接\r\n当前链接状态:" + this.readyState); };
ws.onmessage = function (event) { alert("接收到服务器发送的数据:\r\n" + event.data); };
ws.onclose = function (event) { alert("已经与服务器断开链接\r\n当前链接状态:" + this.readyState); };
ws.onerror = function (event) { alert("WebSocket异常!"); };

还能够经过send的方式发送消息

ws.send("Hello World");

WebSocket具备较为复杂的协议,须要在服务端作额外编程才能进行数据通信。有关协议的详细内容,我会在之后的文章中进行解释。

 

WebSocket + MessageQueue

MessageQueue,简称MQ,也就是消息列队。是一种经常用于Tcp服务端的技术。经过生产和访问各类消息类型,MQ服务器会将生产者所生成的消息发给感兴趣的客户端。市面上有不少的MQ框架,好比:ActiveMQ。

ActiveMQ已经支持了WebSocket协议,也就意味着,WebSocket已经能够做为一个生产者或一个消费者,与MQ服务器链接。

开发者能够经过MQTT的JS脚本,链接上MQ服务器,同时将Web服务器也连上MQ服务器,今后能够告别了Http通信协议,完彻底全使用Socket通信来完成数据的交换。

 


 

总结:

总得来讲,在HTML5规范下,最推荐使用ServerSent和WebSocket的方式进行服务器消息的推送。

对比这两种方式。

ServerSent的方式,可使服务端的开发依然依用之前的方式,可是其工做方式与Comet相似。

而WebSocket的方式,则对服务端的开发有着较高的要求,但其工做方式是彻底的推送。

我本人其实挺偏向WebSocket + MQ的工做方式,可是对于老项目的翻新,仍是用SeverSent比较好

 


结尾

本文为做者原创,转载请注明出处:http://www.cnblogs.com/ShimizuShiori/p/5464063.html

文章中的相关代码能够在 http://j.zizhusoft.com/Develop/Explorer.aspx 中的ServerSent目录中查看

相关文章
相关标签/搜索