导航:首页 > IDC知识 > 服务器推送技术

服务器推送技术

发布时间:2020-07-21 22:47:30

1、使用第三方推送服务相比自己搭建推送服务器有哪些优点和缺点?

看自己推送的服务有哪些,

如果你要推送的服务为价格A+1

你自己搭建推送服务为A+2

相对比自己搭建不发算 如果是长期需要推送服务 就可以选择自己搭建

自己和第三方推送的优势:

第一第三方比自己早一步建立的人脉和推送渠道
自己刚搭建没有这些的所以要浪费很多时间和金钱去建立渠道和人脉

第二 第三方推送服务器相对比自己搭建的推送服务要成熟
对自己刚搭建有很多不懂

2、推送服务是什么

推送技术的基础思想是将浏览器主动查询信息改为服务器主动发送信息。

服务器发送一批数据,浏览器显示这些数据,同时保证与服务器的连接。当服务器需要再次发送一批数据时,浏览器显示数据并保持连接。以后,服务器仍然可以发送批量数据,浏览器继续显示数据,依次类推。

客户端拉曳 (Client Pull)

在客户端拖曳技术中,服务器发送一批数据,在HTTP响应或文档头标记中插入指令,让浏览器“在5秒内再次装入这些数据”或“10秒内前往某URL装入数据”。当指定的时间达到时,客户端就按照服务器的指示去做,或者刷新当前数据,或者调入新的数据。

其实push 和 pull 这两种技术手段非常不同,但目的几乎一致,都是为了给最终用户方便的提供最新信息。

在服务器推送技术中,HTTP 连接一直保持着,直到服务器知道自己已结束发送数据并发送一个结束信号,或者客户端中断连接。而在客户端拖曳技术中,并不保持HTTP连接,相反,客户端被告知合时建立新连接,以及建立连接是获取什么数据。

在服务器推送中,奇妙之处在于“multipart/mixed”格式的 MIME,它能够使一个报文(或HTTP响应)包含许多数据项、在客户端拖曳中,奇妙之处在于HTTP响应头标(或等效的HTML元素),它能告知客户端在指定的延时时间后执行何种动作。

服务器推送通常效率要比客户端拖曳效率高,因为它不必为后续数据建立新的连接。由于始终保持连接,即使没有数据传输时也是这样,因此服务器必须愿意分配这些TCP/IP端口,对于TCP/IP端口数有限的服务器这将是一个严重的问题。

客户端拖曳效率低,因为这必须每次为传送数据建立新的连接。但是它不必始终保持连接。

在实际情况中,建立HTTP连接通常需要花费相当多的时间,多达一秒甚至更多。因此从性能上考虑,服务器推送对于最终用户更有吸引力,特别是对于需要经常更新信息的情况下。

服务器推送相对客户端拖曳的另一点优势是,服务器推送相对比较容易控制。例如,服务器每一次推送时都保持一个连接,但它又随时可以关闭其中的任何连接,而不需要在服务器上设置特殊的算法。而客户端拖曳在同样的情况下要麻烦许多,它每次要与服务器建立连接,服务器为了处理将客户端拖曳请求与特定的最终用户匹配等情况,需要使用相当麻烦的算法。

如果实现服务器推送的CGI程序是使用Shell脚本语言编写的,有时会存在一些问题。例如,客户端最终用户中断连接,Shell程序通常不能注意到,这将使资源毫无用处的浪费掉,解决这一问题的办法是用Perl或者C来编写这类CGI程序,以使用户中断连接时能够结束运行。

如上所述,在服务器推送中,多个响应中连接始终保持,使服务器可在任何时间发送更多的数据。一个明显的好处是服务器完全能够控制更新数据的时间和频率。另外,这种方法效率高,因为始终保持连接。缺点是保持连接状态会浪费服务器端的资源。服务器推送还比较容易中断。

3、请问RSS的推送技术究竟是怎么回事?

看一看这个吧,朋友看有没有用.

推送技术的基础思想是将浏览器主动查询信息改为服务器主动发送信息。服务器发送一批数据,浏览器显示这些数据,同时保证与服务器的连接。当服务器需要再次发送一批数据时,浏览器显示数据并保持连接。以后,服务器仍然可以发送批量数据,浏览器继续显示数据,依次类推。?

客户端拉曳(Client?Pull)?

在客户端拖曳技术中,服务器发送一批数据,在HTTP响应或文档头标记中插入指令,让浏览器“在5秒内再次装入这些数据”或“10秒内前往某URL装入数据”。当指定的时间达到时,客户端就按照服务器的指示去做,或者刷新当前数据,或者调入新的数据。?

其实push?和?pull?这两种技术手段非常不同,但目的几乎一致,都是为了给最终用户方便的提供最新信息。?

在服务器推送技术中,HTTP?连接一直保持着,直到服务器知道自己已结束发送数据并发送一个结束信号,或者客户端中断连接。而在客户端拖曳技术中,并不保持HTTP连接,相反,客户端被告知合时建立新连接,以及建立连接是获取什么数据。?

在服务器推送中,奇妙之处在于“multipart/mixed”格式的MIME,它能够使一个报文(或HTTP响应)包含许多数据项、在客户端拖曳中,奇妙之处在于HTTP响应头标(或等效的HTML元素),它能告知客户端在指定的延时时间后执行何种动作。?

服务器推送通常效率要比客户端拖曳效率高,因为它不必为后续数据建立新的连接。由于始终保持连接,即使没有数据传输时也是这样,因此服务器必须愿意分配这些TCP/IP端口,对于TCP/IP端口数有限的服务器这将是一个严重的问题。?

客户端拖曳效率低,因为这必须每次为传送数据建立新的连接。但是它不必始终保持连接。?

在实际情况中,建立HTTP连接通常需要花费相当多的时间,多达一秒甚至更多。因此从性能上考虑,服务器推送对于最终用户更有吸引力,特别是对于需要经常更新信息的情况下。?

服务器推送相对客户端拖曳的另一点优势是,服务器推送相对比较容易控制。例如,服务器每一次推送时都保持一个连接,但它又随时可以关闭其中的任何连接,而不需要在服务器上设置特殊的算法。而客户端拖曳在同样的情况下要麻烦许多,它每次要与服务器建立连接,服务器为了处理将客户端拖曳请求与特定的最终用户匹配等情况,需要使用相当麻烦的算法。?

如果实现服务器推送的CGI程序是使用Shell脚本语言编写的,有时会存在一些问题。例如,客户端最终用户中断连接,Shell程序通常不能注意到,这将使资源毫无用处的浪费掉,解决这一问题的办法是用Perl或者C来编写这类CGI程序,以使用户中断连接时能够结束运行。?

如上所述,在服务器推送中,多个响应中连接始终保持,使服务器可在任何时间发送更多的数据。一个明显的好处是服务器完全能够控制更新数据的时间和频率。另外,这种方法效率高,因为始终保持连接。缺点是保持连接状态会浪费服务器端的资源。服务器推送还比较容易中断。?

接下来就大概说说服务器推送技术?
服务器在响应请求时,HTTP使用MIME报文格式来封装数据。通常一个HTTP响应只能包含一个数据块。但MIME有一种机制可用一个报文(或HTTP响应)表示将多个数据块,这种机制就是成为“multipart/mixed”的标准MIME类型。multipart/mixed报文大体格式如下:?
Content-type:multipart/mixed;boundary=ThisRandomString?
--ThisRandomString?
Content-type:text/plain?
第一个对象的数据。?
--ThisRandomString?
Content-type:text/plain?
第二个对象的数据。?
--ThisRandomString--?

上述报文包括两上数据块,二者的类型都是“text/plain”。最后一个“ThisRandomString”后的两条短线(--)表示报文结束,后面没有数据。?

对于服务器推送,使用一个“multipart/mixed”类型的变种--multipart/x-mixed-replace。这里,“x-”表示属于实验类型。“replace”表示每一个新数据块都会代替前一个数据块。也就是说,新数据不是附加到旧数据之后,而是替代它。?

下面是实际使用的“multipart/x-mixed-replace”类型:?
Content-type:multipart/x-mixed-replace;boundary=ThisRandomString?
--ThisRandomString?
Content-type:text/plain?
第一个对象的数据?
--ThisRandomString?
Content-type:text/plain?
第二个(最后一个)对象的数据。?
--ThisRandomString--?
使用这一技术的关键是,服务器并不是推送整个“multipart/x-mixed-replace”报文,而是每次发送后数据块。?
HTTP连接始终保持,因而服务器可以按自己需要的速度和频率推送新数据,两个数据块之间浏览器仅需在当前窗口等候,用户甚至可以到其他窗口做别的事情,当服务器需要发送新数据时,它只是源(ABC输入法没那个字*&^$#)传输管道发送数据块,客户端相应的窗口进行自我更新。?

在服务器推送技术中,“multipart/x-mixed-replace”类型的报文由唯一的边界线组成,这些边界线分割每个数据块。每个数据块都有自己的头标,因而能够指定对象相关的内容类型和其他信息。由于“multipart/x-mixed-replace”的特性是每一新数据块取代前一数据对象,因而浏览器中总是显示最新的数据对象。?
“multipart/x-mixed-replace”报文没有结尾。也就是说,服务器可以永远保持连接,并发送所需的数据。如果用户不再在浏览器窗口中显示数据流,或者浏览器到服务器间的连接中间(例如用户按“STOP”按钮),服务器的推送才会中断。这是人们使用服务器推送的典型方式。?

当浏览器发现“Content-type”头标或到达头标结束处时,浏览器窗口中的前一个文档被清除,并开始显示下一个文档。发现下一个报文边界时,就认为当前数据块(文档)已经结束。?
总之,服务器推送的数据由一组头标(通常包括“Content-type”)、数据本身和分割符(报文边界)三部分组成。浏览器看到分割符时,它保持状态不变,直到下一个数据块到达。?

4、html5现在可以实现服务器推送了吗

对于某些类型的应用来说,服务器推送事件是最佳的选择。本文对服务器推送技术进行了详细的介绍,包含浏览器端和服务器端的相应实现细节,为在实践中使用该技术提供了指南。

对于一般的 Web 应用开发,大多数开发人员并不陌生。在 Web 应用中,浏览器和服务器之间使用的是请求 / 响应的交互模式。浏览器发出请求,服务器根据收到的请求来生成相应的响应。浏览器再对收到的响应进行处理,展现给用户。响应的格式可能是 HTML、XML 或 JSON 等。随着 REST 架构风格和 AJAX 的流行,服务器更多地使用 JSON 作为响应的数据格式。Web 应用使用 XMLHttpRequest 对象来发送请求,并根据服务器端返回的数据,对页面的内容进行动态更新。通常来说,用户在页面上的操作,比如点击或移动鼠标,会触发相应的事件。由 XMLHttpRequest 对象来发出请求,得到服务器响应之后进行页面的局部更新。这种方式的不足之处在于:服务器端产生的数据变化不能及时地通知浏览器,而是需要等到下次请求发出时才能被浏览器获取。对于某些对数据实时性要求很高的应用来说,这种延迟是不能接受的。
为了满足这类应用的需求,就需要有某种方式能够从服务器端推送数据给浏览器,以保证服务器端的数据变化可以在第一时间通知给用户。目前常见的解决办法有不少,主要可以分成两类。这两类方法的区别在于是否基于 HTTP 协议来实现。不使用 HTTP 协议的做法是使用 HTML 5 新增的 WebSocket 规范,而使用 HTTP 协议的做法则包括简易轮询、COMET 技术和本文中要介绍的 HTML 5 服务器推送事件。下面会对这几种技术进行介绍。
简介
在介绍 HTML 5 服务器推送事件之前,首先介绍一些上面提到的几种服务器端数据推送技术。第一种是 WebSocket。WebSocket 规范是 HTML 5 中的一个重要组成部分,已经被很多主流浏览器所支持,也有不少基于 WebSocket 开发的应用。正如名称所表示的一样,WebSocket 使用的是套接字连接,基于 TCP 协议。使用 WebSocket 之后,实际上在服务器端和浏览器之间建立一个套接字连接,可以进行双向的数据传输。WebSocket 的功能是很强大的,使用起来也灵活,可以适用于不同的场景。不过 WebSocket 技术也比较复杂,包括服务器端和浏览器端的实现都不同于一般的 Web 应用。
除了 WebSocket 之外,其他的实现方式是基于 HTTP 协议来达到实时推送的效果。第一种做法是简易轮询,即浏览器端定时向服务器端发出请求,来查询是否有数据更新。这种做法比较简单,可以在一定程度上解决问题。不过对于轮询的时间间隔需要进行仔细考虑。轮询的间隔过长,会导致用户不能及时接收到更新的数据;轮询的间隔过短,会导致查询请求过多,增加服务器端的负担。
COMET 技术改进了简易轮询的缺点,使用的是长轮询。长轮询的方式在每次请求时,服务器端会保持该连接在一段时间内处于打开状态,而不是在响应完成之后就立即关闭。这样做的好处是在连接处于打开状态的时间段内,服务器端产生的数据更新可以被及时地返回给浏览器。当上一个长连接关闭之后,浏览器会立即打开一个新的长连接来继续请求。不过 COMET 技术的实现在服务器端和浏览器端都需要第三方库的支持。
综合比较上面提到的 4 种不同的技术,简易轮询由于其本身的缺陷,并不推荐使用。COMET 技术并不是 HTML 5 标准的一部分,从兼容标准的角度出发,也不推荐使用。WebSocket 规范和服务器推送技术都是 HTML 5 标准的组成部分,在主流浏览器上都提供了原生的支持,是推荐使用的。不过 WebSocket 规范更加复杂一些,适用于需要进行复杂双向数据通讯的场景。对于简单的服务器数据推送的场景,使用服务器推送事件就足够了。
在浏览器支持方面,服务器推送事件已经在除 IE 外的大部分桌面和移动浏览器上得到了支持。支持服务器推送事件的浏览器及其版本包括:Firefox 6.0+、Chrome 6.0+、Safari 5.0+、Opera 11.0+、iOS Safari 4.0+、Opera Mobile 11.1+、Chrome for Android 25.0+、Firefox for Android 19.0+ 以及 Blackberry Browser 7.0+ 等。关于 IE 的支持,在下面的章节中有详细的介绍。
下面对服务器推送事件的规范进行具体的说明。
规范
Server-sent Events 规范是 HTML 5 规范的一个组成部分,具体的规范文档见参考资源。该规范比较简单,主要由两个部分组成:第一个部分是服务器端与浏览器端之间的通讯协议,第二部分则是在浏览器端可供 JavaScript 使用的 EventSource 对象。通讯协议是基于纯文本的简单协议。服务器端的响应的内容类型是“text/event-stream”。响应文本的内容可以看成是一个事件流,由不同的事件所组成。每个事件由类型和数据两部分组成,同时每个事件可以有一个可选的标识符。不同事件的内容之间通过仅包含回车符和换行符的空行(“\r\n”)来分隔。每个事件的数据可能由多行组成。代码清单 1 给出了服务器端响应的示例。
清单 1. 服务器端响应的示例
data: first event

data: second event
id: 100

event: myevent
data: third event
id: 101

: this is a comment
data: fourth event
data: fourth event continue

如代码清单 1 所示,每个事件之间通过空行来分隔。对于每一行来说,冒号(“:”)前面表示的是该行的类型,冒号后面则是对应的值。可能的类型包括:
类型为空白,表示该行是注释,会在处理时被忽略。
类型为 data,表示该行包含的是数据。以 data 开头的行可以出现多次。所有这些行都是该事件的数据。
类型为 event,表示该行用来声明事件的类型。浏览器在收到数据时,会产生对应类型的事件。
类型为 id,表示该行用来声明事件的标识符。
类型为 retry,表示该行用来声明浏览器在连接断开之后进行再次连接之前的等待时间。
在代码清单 1 中,第一个事件只包含数据“first event”,会产生默认的事件;第二个事件的标识符是 100,数据为“second event”;第三个事件会产生类型为“myevent”的事件;最后一个事件的数据为“fourth event\nfourth event continue”。当有多行数据时,实际的数据由每行数据以换行符连接而成。
如果服务器端返回的数据中包含了事件的标识符,浏览器会记录最近一次接收到的事件的标识符。如果与服务器端的连接中断,当浏览器端再次进行连接时,会通过 HTTP 头“Last-Event-ID”来声明最后一次接收到的事件的标识符。服务器端可以通过浏览器端发送的事件标识符来确定从哪个事件开始来继续连接。
对于服务器端返回的响应,浏览器端需要在 JavaScript 中使用 EventSource 对象来进行处理。EventSource 使用的是标准的事件监听器方式,只需要在对象上添加相应的事件处理方法即可。EventSource 提供了三个标准事件,如表 1 所示。
表 1. EventSource 对象提供的标准事件

名称
说明
事件处理方法

open 当成功与服务器建立连接时产生 onopen
message 当收到服务器发送的事件时产生 onmessage
error 当出现错误时产生 onerror
如之前所述,服务器端可以返回自定义类型的事件。对于这些事件,可以使用 addEventListener 方法来添加相应的事件处理方法。代码清单 2 给出了 EventSource 对象的使用示例。
清单 2. EventSource 对象的使用示例
var es = new EventSource('events');
es.onmessage = function(e) {
console.log(e.data);
};

es.addEventListener('myevent', function(e) {
console.log(e.data);
});

如代码清单 2 所示,在指定 URL 创建出 EventSource 对象之后,可以通过 onmessage 和 addEventListener 方法来添加事件处理方法。当服务器端有新的事件产生,相应的事件处理方法会被调用。EventSource 对象的 onmessage 属性的作用类似于 addEventListener( ‘ message ’ ),不过 onmessage 属性只支持一个事件处理方法。
在介绍完服务器推送事件的规范内容之后,下面介绍服务器端的实现。

5、php如何实现服务器推送技术,即时把信的数据发送到客户端。

主要有三种方案
第一种是利用第三方的API来实现信息推送,主要包括环信、百度云推送、leancloud等
第二种通过javascript的setTimeout或者setInterval来实现,同理PHP端也可以用守护进程来实现
第三种通过Linux的计划任务来实时推送需要消息

6、推送技术的评价标准

推送方案的公认评价采取4s标准:1.Safe(安全) 2. Stable(稳定) 3.Save(省电省流量省成本) 4.Slim(体积小) 推送方案应支持透传及各种加密方案,保障信息传递安全。
推送方案的ID系统应该独立于已有的网站或服务的ID系统,这样保障用户在不同手机上登录后的信息投递准确性,避免因为取消绑定事件失败因网络传输而造成的信息误投送。 稳定包括两个部分一个是服务器端的稳定性,一个是手机端的稳定性。
服务端稳定性,因为使用长连接方案,对服务器的开销和要求很大,推送方案对服务器开发要求很高,海量线程连接下的服务器稳定性是非常具有挑战性的。一般的评判标准包括:
- 同时在线时峰值 (一般按照百万并发连接时服务器稳定性评测)
- 高并发时消息平均延迟时间(一般按照1分钟处理1百万条信息评测)
- 服务稳定性 (一般要求全年99.9%以上可用,有备份,有负载均衡等)
鉴于服务器稳定的开发难度很大,小团队不建议自己开发,建议使用稳定的第三方推送方案,如个推,蝴蝶等。
手机端的稳定性,主要是因为中国的复杂网络状况及手机型号适配情况造成手机长时间稳定联网较困难,所以稳定性非常重要,一般的评判标准包括:
- 每日联网23.5小时以上用户比例 (表征联网稳定性)
- 消息发送后9小时内收到率 (表征到达率)
一般来说,推送方案要做网络的分运营商,分省,分机型适配,自己开发工作量较大
3.Save(节省)
省电应注意CPU休眠,一般用服务缩短待机时间百分比评判
省流量应注意协议的修改和冗余数据包的处理,一般用空载待机月流量评判
省成本应考虑单服务器承载同时连接数,可承载同时连接数越多成本越低,业内 顶尖水平为个推的单服务器50万连接
4.Slim(体积小)
推送服务应该体积尽量小,不影响主程序的大小和复杂度,一般以小于300K为宜。

7、推送机制和后台的区别?

像wp7和IOS都有一个系统级的消息服务,这个消息服务是和服务器保持了一下长连接,然后服务器有信息可以随时发给你。这个消息中包含了消息的内容,归属,也就是这条消息是属于谁的。这个消息服务的是整个系统。
后台的话就是自助餐,你都是自己去服务器取,看看盘子里有没有食物。有的话就端回来。没有就一个劲儿去看。这个比较耗资源。流量和电量等。

基本上是可以这样理解的。说的也不是特别的好。

8、数据实时推送怎么实现

Ajax 技术已经存在了一段时间,开发的动力已经真正开始得到了人们的认可。越来越多的 Web 站点正在考虑使用Ajax 进行设计,开发人员也开始将 Ajax 的能力发挥到极限。随着社交网络和协作式报告等现象的出现,一组全新的要求浮现出来。如果有其他用户更改了某位用户正在观察的任何活动,则用户希望得到通知。如果一个 Web 站点显示动态数据,如股价等,那么所有用户都必须立即得到关于变更的通知。
这些场景本身属于一类称为 “服务器推送” 的问题。通常,服务器是中心实体,服务器将首先获得关于所发生的任何更改的通知,服务器负责将此类更改通知所有连接的客户端。但遗憾的是,HTTP 是客户端-服务器通信的标准协议,它是无状态的,而且在某种意义上来说,也是一种单向的协议。HTTP 场景中的所有通信都必须由客户端发起,至服务器结束,然而我们所提到的场景的需求则完全相反。对于服务器推送来说,需要由服务器发起通信,并向客户端发送数据。HTTP 协议并无相关配置,Web 站点应用程序开发人员使用独创的方法来绕过这些问题,例如轮询,客户端会以固定(或可配置)的时间间隔与服务器联系,查找是否有新更新可用。在大多数时候,这些轮询纯粹是浪费,因而服务器没有任何更新。这种方法不是没有代价的,它有两大主要问题。
这种方法极度浪费网络资源。每一个轮询请求通常都会创建一个 TCP 套接字连接(除非 HTTP 1.1 将自己的keepAlive 设置为 true,此时将使用之前创建的套接字)。套接字连接本身代价极高。除此之外,每一次请求都要在网络上传输一些数据,如果请求未在服务器上发现任何更新,那么这样的数据传输就是浪费资源。如果在客户端机器上还运行着其他应用程序,那么这些轮询会减少传输数据可用的带宽。
即便是请求成功,确实为客户端传回了更新,考虑到轮询的频率,这样的更新也不是实时的。例如,假设轮询配置为每 20 秒一次,就在一次请求刚刚从服务器返回时,发生了更新。那么这次更新将在 20 秒后的下一次请求到来时才能返回客户端。因而,服务器上准备好供客户端使用的更新必须等待一段时间,才能真正地为客户端所用。对于需要以尽可能实时的方式运行的应用程序来说,这样的等待是不可接受的。
考虑到这样两个问题,对于需要关键、实时的服务器端更新的企业应用程序而言,轮询并不是最理想的方法。在这篇文章中,我将介绍多种可以替代轮询的方法。每一种替代方法在某些场景中都有自己的突出之处。我将说明这些场景,并展示需要实时服务器推送的一组 UI。
Ajax 应用程序中的服务器更新技术
让我们来具体看看用于更新来自服务器的信息的一些常用技术,这些技术模拟了服务器推送。
短轮询
短轮询也称为高频轮询,就是我在本文开头处介绍的技术。这种方法在以下情况中表现最好:
有足够的带宽可用。
根据统计数据,大多数时候,请求都能获得更新。例如,股市数据就总是有可用更新。
使用 HTTP 1.1 协议。设置 keepAlive=true,因而,同一个套接字连接始终保持活动状态,并可重用。
长轮询
长轮询是用于更新服务器数据的另外一种方法。这种方法的理念就是客户端建立连接,服务器阻塞连接(通过使请求线程在某些条件下处于等待状态),有数据可用时,服务器将通过阻塞的连接发送数据,随后关闭连接。客户端在接收到更新后,立即重新建立连接,服务器重复上述过程,以此实现近于实时的通信。然而,长轮询具有以下缺陷:
一般的浏览器默认允许每台服务器具有两个连接。在这种情况下,一个连接始终是繁忙状态。因而,UI 只有一个连接(也就是说,能力减半)可用于为用户请求提供服务。这可能会导致某些操作的性能降低。
仍然需要打开和关闭 HTTP 连接,如果采用的是非持久连接模式(keepAlive=false),那么这种方法的代价可能极高。
这种方法近于实时,但并非真正的实时。(当然,某些外部因素总是不可控的,比如网络延时,在任何方法中都会存在这些因素。)
流通道
流通道(streaming channel)与长轮询大致相同,差别在于服务器不会关闭响应流。而是特意保持其处于打开状态,使浏览器认为还有更多数据即将到来。但是,流通道也有着自己的缺陷:
最大的问题就是数据刷新(flushing)。过去,Web 服务器会缓存响应数据,仅在接受到足够的字节数或块数后才会发送出去。在这种情况下,即便应用程序刷新数据,也仍然会由服务器缓存,以实现优化。更糟的是,如果在客户端和服务器之间存在代理服务器,那么代理也可能会为自身之便缓存数据。
如果发现套接字将打开较长的时间,某些浏览器实现可能会自行决定关闭套接字。在这种情况下,通道需要重新建立。
通常,第一个问题可通过为每个流响应附加垃圾有效载荷来解决,使响应数据足以填满缓冲区。第二个问题可通过“保持活动” 或按固定间隔 “同步” 消息来欺瞒浏览器,使浏览器认为数据是以较慢的速率传入的。
这些解决方案适用的用例范围狭窄。所有这些方法都已经在 Internet 上的某些解决方案中得到了应用。然而,这些解决方案都遭遇了相同的问题:缺乏可伸缩性。典型情况下,要阻塞一个请求,需要阻塞处理请求的线程,因为如今几乎所有应用服务器都会执行阻塞 I/O。即便不是这样,Java™ 2 Platform, Enterprise Edition (J2EE) 也未提供为 HTTP 请求和响应执行非阻塞 I/O 的标准。(Servlets 3.0 API 可解决这一问题,因为这些 API 中包含Comet Servlet。)
至此,需要具备非阻塞 I/O(NIO)服务器,客户端应用程序通过它进行连接。由于此类套接字是纯 TCP 二进制套接字,因而将实现以下目标:
由于服务器端具有 NIO,因而可实现更高的可伸缩性。
响应缓存的问题不复存在,因为这个套接字直接受应用程序的控制。
基于上述说明,有必要指出这种方法的四个缺点:
由于使用的是二进制 TCP 套接字,因而应用程序无法真正地利用 HTTPS 层提供的 SSL 安全性。所以,要求数据安全性的应用程序可能需要提供自己的加密工具。
通常情况下,服务器套接字将在 80 以外的端口上运行,如果防火墙仅允许来自端口 80 的流量,将出现问题。因而,可能需要进行一些端口配置。
Ajax 客户端无法通过后端打开 TCP 套接字连接。
即便 Ajax 客户端能够执行 open 函数,也无法理解二进制内容,这是因为 Ajax 使用的是 XML 或 JSON(基于文本)格式。
在这篇文章中,要强调的是如何真正地绕开第三个和第四个问题。如果能够处理安全性和防火墙问题,那么其他问题也能得到处理。这种做法的获益极为显著。
可为应用程序实现最大程度的实时服务器推送行为(不考虑网络延时等外部因素),将获得高度可伸缩的解决方案(以同时连接的客户端数量为准)。
下面解决上述的第三个和第四个问题。
基于套接字的 RIA 技术
Ajax 并不能真正地解决第三个和第四个问题。因而,需要利用其他 RIA 技术寻求解决方案。有两种 RIA 技术提供的套接字 API 可与 Ajax 应用程序交互。这两种技术是 Adobe Flex 和 OpenLaszlo。全面介绍这两种技术并非本文讨论范围之内,但这些技术提供的两种特性如下所示:
均能通过后端打开 TCP 二进制套接字
均能出色地与运行在同一个浏览器窗口中的 Ajax 应用程序(主要是 JavaScript)交互
但这仅仅解决了部分问题。确实可以打开套接字,可以使 Ajax 应用程序使用它们,但 Ajax 应用程序仍然无法处理纯二进制数据。实际上,这两种技术都提供了二进制 TCP 套接字的一种变体,称为XMLSocket,它可用于来回传输纯 XML 数据。这正是您需要的东西。如果这些技术能够通过服务器打开套接字,如果它们能够传输 XML 数据,任务就完成了。Ajax 应用程序可充分利用这一点,模拟实时服务器推送技术。下面将介绍如何实现。
实现 Ajax 服务器推送
将使用两种工具解释这项技术:Adobe Flex 和 OpenLaszlo。首先,需要编写能够接收并缓存连接的后端服务器。在这里不能太过偏离主题,因而要保证服务器基于阻塞 I/O。
需要创建一个服务器套接字,接收预先指定地址的连接:
清单 1. 创建服务器套接字
public class SimpleServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress("localhost",20340));
Socket socket = serverSocket.accept();
}
}
在这里,将服务器套接字绑定到 localhost:20340 这一地址。当一个客户端连接到该服务器套接字时,它将为我提供一个套接字,显示连接。Flex 客户端随后会要求策略文件,这是其安全性模型的一部分。通常,这个策略文件的形式类似于清单 2。
清单 2. Flex 客户端策略文件
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*" to-ports="20340"/>
</cross-domain-policy>
就在连接之后,Flex 客户端会立即发送一条策略文件的请求。该请求仅包含一个 XML 标记:<policy-file-request/>。在响应中,您需要返回此策略文件。清单 3 中的代码就完成了这个任务。
清单 3. 发送策略文件响应
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress("localhost", 20340));
Socket socket = serverSocket.accept();
String POLICY_REQUEST = "<policy-file-request/>\u0000";
String POLICY_FILE = "<?xml version=\"1.0\"?>\n" +
"<!DOCTYPE cross-domain-policy SYSTEM
\"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\">\n" +
"<cross-domain-policy> \n" +
" <allow-access-from domain=\"*\" to-ports=\"20340\"/> \n" +
"</cross-domain-policy>";
byte[] b = new byte[POLICY_REQUEST.length()];
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
dataInputStream.readFully(b);
String request = new String(b);
if (POLICY_REQUEST.equals(request)) {
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.write(POLICY_FILE.getBytes());
dataOutputStream.flush();
dataOutputStream.close();
} else throw new IllegalArgumentException("unknown request format " + request);
}
此代码建立了与客户端的成功连接。现在,服务器可以与客户端发起 “握手” 之类的协议,此时,服务器通常会指定一个惟一的 ID,并将其发送给客户端,此后,服务器可根据 ID 缓存套接字,在此之后,如果服务器需要向客户端推送某些数据,可以按照 ID 定位套接字,并使用其输出流。幸运的是,OpenLaszlo 也使用了相同的基于策略文件的机制,因而,同样的服务器代码适用于两种场景。
下面将介绍如何创建 Flex 套接字,随后将其与 Ajax 应用程序连接。
使用 Adobe Flex 打开客户端套接字
清单 4 中的代码展示了如何通过 Flex 打开客户端套接字:
清单 4. 通过 Flex 打开客户端
var socket : XMLSocket = new XMLSocket();
// register events:
socket.addEventListener(Event.CLOSE, closehandler);
socket.addEventListener(Event.CONNECT, connectHandler);
socket.addEventListener(Event.OPEN, openHandler);
socket.addEventListener(ProgressEvent.SOCKET_DATA, readHandler);
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
socket.connect("localhost",20340);
完成 socket.connect() 调用后,Flex 将向服务器发送一条请求,要求提供策略文件,期待获得 XML 响应。完成之后,连接即建立,这个套接字现在即可用于从服务器推送数据。
作为拼图的最后一块,将看到 Flex 如何将 Ajax 作为应用程序调用。为此,要编写一个可处理服务器端消息的通用 JavaScript 函数。将此方法命名为 handleServerMessageReceived(message)。此方法会获取来自服务器的 XML 代码,此方法对于消息的处理方式以应用程序为依据。清单 5 中的代码展示了 Flex 如何调用 JavaScript函数。这是 readHandler 方法的代码,该方法在接收到服务器 XML 消息时被调用。
清单 5. 使用 handleServerMessageReceived(message) 的 readhHandler 代码
public function readHandler(e : DataEvent) : void {
var message: XML = e.data as XML;
ExternalInterface.call("handleServerMessageReceived", message);
}
就是这样!就是这样简单。已经创建了一个 XML 套接字连接。当来自服务器的数据送达时,可调用 Ajax 中的某些通用处理函数,处理这些消息。完整源代码可供下载(请参见下载部分)。
下面来看看 OpenLaszlo 如何实现相同的目标。
使用 OpenLaszlo 打开客户端套接字
由于 OpenLaszlo 应用程序以 Flash 和 DHTML 平台为目标,因而其 API 和脚本语言类似于 Flash 和JavaScript。这主要是为希望迁移到 OpenLaszlo(作为 RIA 的替代方案)的 Web 开发人员提供便利。
OpenLaszlo 提供了两种创建与后端之间的持久连接的方法。一种方法要使用 Lz(Laszlo 的缩写)标准库中提供的ConnectionManager API。但其文档明确说明了以下内容:
“警告:这项特性是临时的。此特性用于容量有限的环境,能够用于开发,但我们不推荐使用此特性进行部署(不包括低容量、非任务关键型的部署)。若对使用此版本的持久连接的应用程序的健壮性有任何问题,请直接咨询Laszlo Systems。”
或许目前这是一项实验技术,但在未来的 OpenLaszlo 版本中,它将得到证实。
第二种方法与 Flex 相似,您要手动打开 XML 套接字连接,等待 READ_DATA 事件发生。清单 6 展示了实现方法。
清单 6. 定义 XMLSocket 类
<class name="ClientSocket" extends="node">
<attribute name="host" />
<attribute name="port" />
<XMLSocket name='xml_socket'/>
<handler name="oninit">
// connect the socket here:
xml_socket.connect(host,port);
</handler>
<handler name='onData' reference='xml_socket' args='messageXML'>
<![CDATA[
ExternalInterface.call(‘handleServerMessageReceived',messageXML);
]]>
</method>
</class>
(为简短起见,忽略了其他处理方法。在本文的下载部分中可获得完整的代码清单。)
就是这样,创建一个套接字对象并连接此对象就是这样轻松。这一代码清单创建了一个名为 ClientSocket 的新类,随后声明了一个名为 “xml_socket” 的 XML 套接字对象。只要此套接字对象读取到来自服务器的数据,就会触发onData 事件,该事件将由为 onData 定义的处理方法处理。最后,在 onData 处理方法中,调用 Ajax 应用程序中的外部 JavaScript 函数。此后的流程与 Flex 客户端相同。
要创建 ClientSocket 对象,只需声明它即可:
清单 7. 声明 ClientSocket
<canvas>
<ClientSocket id='serverPushSocket' host='localhost' port='20340'/>
</canvas>
为 ClientSocket 触发了 init 事件时,将尝试连接指定主机和端口的后端。(请参见清单 6 中的 oninit 处理方法。)
结束语
这篇文章讨论了几种模拟服务器推送的方法,从纯轮询到实时服务器推送,文中说明了每种方法的优缺点。最后,重点关注了能够提供最优服务器可伸缩性和实时服务器推送行为的方法。
服务器推送并非适用于每一个应用程序。实际上,大多数应用程序都非常适合普通的请求/响应场景。其他一些应用程序使用轮询和类似的技术足以满足需求。只有那些服务器更新极为重要、客户端需要得到即时通知的重量级应用程序才需要本文所述技术。有必要再次强调,这种技术有两个主要的缺点:
如果数据需要通过 HTTPS 传输,客户端套接字无法利用 SSL 加密工具。
防火墙需要允许客户端套接字通过非标准端口(非 80 端口)连接到服务器。
然而,市面上存在着大量开源库,可利用它们轻松编写自定义的加密例程。类似地,配置防火墙也是轻而易举的,实际上,只需付出很少的代价,即可获得强大的实时服务器推送功能。

9、推送技术的一般应用

推送服务通常是在事先表达喜好的信息。这就是所谓的发布/订阅模型。一个客户端可能“订阅”的各种信息“通道”。每当新的内容可以在这些渠道之一,服务器会推出的信息给用户。
同步会议和即时消息是推动服务的典型例子。邮件和聊天,有时文件推到了只要他们是由信息服务受到了用户。同行都分散的对等程序(如废物),并集中程序(如IRC或XMPP协议)允许推送文件,这意味着发送者发起数据传输,而不是接受者。
电邮也是一个推动系统:SMTP协议的基础上,它是一个推动协议(见PushMail)。不过,最后一步,从邮件服务器到桌面计算机通常使用的POP3或IMAP像拉协议。现代电子邮件客户端走这一步似乎瞬间通过反复投票的邮件服务器,经常检查新邮件了。 IMAP协议包括IDLE命令,它允许服务器告诉客户端新邮件到达时。原来的黑莓是第一推技术流行的例子了在无线方面的电子邮件。
另一种普及型互联网推送技术为pointcast公司网络,该网络在1990年代获得了知名度。它传递新闻和股市数据。 Netscape和微软自己的软件集成到它在浏览器大战的高度,但后来逐渐消失,并在与RSS(一拉技术)2000年代取代。
其他用途的Web应用,包括推动市场数据发布(股票行情),在线聊天/消息系统(网上聊天),拍卖,网上博彩和游戏,运动的结果,监测主机和传感器网络监控。

与服务器推送技术相关的知识