一般状况下,不管是web浏览器仍是移动app,咱们与服务器之间的交互都是主动的,客户端向服务器端发出请求,而后服务器端返回数据给客户端,客户端浏览器再将信息呈现,客户端与服务端对应的模式是: 客户端请求--服务端响应,这种机制对于信息变化不是特别频繁的应用尚可,但对于实时要求高、海量并发的应用来讲显得捉襟见肘,尤为在当前业界移动互联网蓬勃发展的趋势下,高并发与用户实时响应是 Web 应用常常面临的问题,好比金融证券的实时信息,Web 导航应用中的地理位置获取,社交网络的实时消息推送,新闻的订阅,天气的提醒等。这些状况下,须要服务器主动推送消息给客户端。html
那么在这样的模式下,会有几个问题须要咱们思考下:java
1.应用服务器如何肯定每个应用所在的设备web
2.服务器端是如何将消息推送到客户端的,客户端又不像服务器有一个固定的地址ajax
带着这些疑问咱们来研究一下目前有哪些技术能够解决该问题:后端
所谓的Ajax轮询,其实就是定时的经过Ajax查询服务端,客户端按规定时间定时像服务端发送ajax请求,服务器接到请求后立刻返回响应信息并关闭链接。跨域
这种技术方式实现起来很是简单,可是这种方式会有很是严重的问题,就是须要不断的向服务器发送消息询问,这种方式会对服务器形成极大的性能浪费。浏览器
还有一个相似的轮询是使用JSONP跨域请求的方式轮询,在实现起来有差异,但基本原理都是相同的,都是客户端不断的向服务器发起请求。服务器
优势websocket
实现简单。网络
缺点
这是经过模拟服务器发起的通讯,不是实时通讯,不顾及应用的状态改变而盲目检查更新,致使服务器资源的浪费,且会加剧网络负载,拖累服务器。
Comet,基于 HTTP 长链接的 "服务器推" 技术,能使服务器端主动以异步的方式向客户端程序推送数据,而不须要客户端显式的发出请求,目前有两种实现方式:
Ajax 的出现使得 JavaScript 能够调用 XMLHttpRequest 对象发出 HTTP 请求,JavaScript 响应处理函数根据服务器返回的信息对 HTML 页面的显示进行更新。使用 AJAX 实现 "服务器推" 与传统的 AJAX 应用不一样之处在于:
基于长轮询的服务器推模型
相对于"轮询"(poll),这种长轮询方式也能够称为"拉"(pull)。由于这种方案基于 AJAX,具备如下一些优势:请求异步发出;无须安装插件;IE、Mozilla FireFox 都支持 AJAX。
长轮询 (long polling) 是在打开一条链接之后保持并等待服务器推送来数据再关闭,能够采用HTTP长轮询和XHR长轮询两种方式:
把 script 标签附加到页面上以让脚本执行。服务器会挂起链接直到有事件发生,接着把脚本内容发送回浏览器,而后从新打开另外一个 script 标签来获取下一个事件,从而实现长轮询的模型。
这种方式是使用比较多的长轮询模式。
客户端打开一个到服务器端的 AJAX 请求而后等待响应;服务器端须要一些特定的功能来容许请求被挂起,只要一有事件发生,服务器端就会在挂起的请求中送回响应并关闭该请求。客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,从新创建链接;如此循环。
如今浏览器已经支持CROS的跨域方式请求,所以HTTP和JSONP的长轮询方式是慢慢被淘汰的一种技术,建议采用XHR长轮询。
优势
客户端很容易实现良好的错误处理系统和超时管理,实现成本与Ajax轮询的方式相似。
缺点
须要服务器端有特殊的功能来临时挂起链接。当客户端发起的链接较多时,服务器端会长期保持多个链接,具备必定的风险。
>>在这里简单的说明下长轮询,长链接的概念 轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后立刻返回响应信息并关闭链接。优势:后端程序编写比较容易。 缺点:请求中有大半是无用,浪费带宽和服务器资源。 实例:适于小型应用。 长轮询:客户端向服务器发送Ajax请求,服务器接到请求后hold住链接,直到有新消息才返回响应信息并关闭链接,客户端处理完响应信息后再向服务器发送新的请求。 优势:在无消息的状况下不会频繁的请求。 缺点:服务器hold链接会消耗资源。 实例:WebQQ、Hi网页版、Facebook IM。 另外,对于长链接和socket链接也有区分: 长链接:在页面里嵌入一个隐蔵iframe,将这个隐蔵iframe的src属性设为对一个长链接的请求,服务器端就能源源不断地往客户端输入数据。 优势:消息即时到达,不发无用请求。 缺点:服务器维护一个长链接会增长开销。 实例:Gmail聊天 Flash Socket:在页面中内嵌入一个使用了Socket类的 Flash 程序JavaScript经过调用此Flash程序提供的Socket接口与服务器端的Socket接口进行通讯,JavaScript在收到服务器端传送的信息后控制页面的显示。 优势:实现真正的即时通讯,而不是伪即时。 缺点:客户端必须安装Flash插件;非HTTP协议,没法自动穿越防火墙。 实例:网络互动游戏。
iframe 是很早就存在的一种 HTML 标记, 经过在 HTML 页面里嵌入一个隐蔵帧,而后将这个隐蔵帧的 SRC 属性设为对一个长链接的请求,服务器端就能源源不断地往客户端输入数据。
基于流方式的服务器推模型
Comet的优缺点
1. Dojo CometD —— http://cometdproject.dojotoolkit.org/
2. DWR —— http://directwebremoting.org/dwr/index.html
3. ICEfaces —— http://www.icefaces.org/main/home/
4. GlassFish Grizzly —— https://grizzly.dev.java.net/
CometD 目前实现 Comet 比较成熟, DWR 弱一些。 ICEfaces 更商业化,实现得很成熟。 Grizzly 是基于GlassFish ,也很成熟。CometD, DWR 开源性好。
不要在同一客户端同时使用超过两个的 HTTP 长链接
咱们使用 IE 下载文件时会有这样的体验,从同一个 Web 服务器下载文件,最多只能有两个文件同时被下载。第三个文件的下载会被阻塞,直到前面下载的文件下载完毕。这是由于 HTTP 1.1 规范中规定,客户端不该该与服务器端创建超过两个的 HTTP 链接, 新的链接会被阻塞。而 IE 在实现中严格遵照了这种规定。
HTTP 1.1 对两个长链接的限制,会对使用了长链接的 Web 应用带来以下现象:在客户端若是打开超过两个的 IE 窗口去访问同一个使用了长链接的 Web 服务器,第三个 IE 窗口的 HTTP 请求被前两个窗口的长链接阻塞。
因此在开发长链接的应用时, 必须注意在使用了多个 frame 的页面中,不要为每一个 frame 的页面都创建一个 HTTP 长链接,这样会阻塞其它的 HTTP 请求,在设计上考虑让多个 frame 的更新共用一个长链接。
服务器端的性能和可扩展性
通常 Web 服务器会为每一个链接建立一个线程,若是在大型的商业应用中使用 Comet,服务器端须要维护大量并发的长链接。在这种应用背景下,服务器端须要考虑负载均衡和集群技术;或是在服务器端为长链接做一些改进。
应用和技术的发展老是带来新的需求,从而推进新技术的发展。HTTP 1.1 与 1.0 规范有一个很大的不一样:1.0 规范下服务器在处理完每一个 Get/Post 请求后会关闭套接口链接; 而 1.1 规范下服务器会保持这个链接,在处理两个请求的间隔时间里,这个链接处于空闲状态。 Java 1.4 引入了支持异步 IO 的 java.nio 包。当链接处于空闲时,为这个链接分配的线程资源会返还到线程池,能够供新的链接使用;当原来处于空闲的链接的客户发出新的请求,会从线程池里分配一个线程资源处理这个请求。 这种技术在链接处于空闲的机率较高、并发链接数目不少的场景下对于下降服务器的资源负载很是有效。
可是 AJAX 的应用使请求的出现变得频繁,而 Comet 则会长时间占用一个链接,上述的服务器模型在新的应用背景下会变得很是低效,线程池里有限的线程数甚至可能会阻塞新的链接。Jetty 6 Web 服务器针对 AJAX、Comet 应用的特色进行了不少创新的改进。
控制信息与数据信息使用不一样的 HTTP 链接
使用长链接时,存在一个很常见的场景:客户端网页须要关闭,而服务器端还处在读取数据的堵塞状态,客户端须要及时通知服务器端关闭数据链接。服务器在收到关闭请求后首先要从读取数据的阻塞状态唤醒,而后释放为这个客户端分配的资源,再关闭链接。
因此在设计上,咱们须要使客户端的控制请求和数据请求使用不一样的 HTTP 链接,才能使控制请求不会被阻塞。
在实现上,若是是基于 iframe 流方式的长链接,客户端页面须要使用两个 iframe,一个是控制帧,用于往服务器端发送控制请求,控制请求能很快收到响应,不会被堵塞;一个是显示帧,用于往服务器端发送长链接请求。若是是基于 AJAX 的长轮询方式,客户端能够异步地发出一个 XMLHttpRequest 请求,通知服务器端关闭数据链接。
在客户和服务器之间保持“心跳”信息
在浏览器与服务器之间维持一个长链接会为通讯带来一些不肯定性:由于数据传输是随机的,客户端不知道什么时候服务器才有数据传送。服务器端须要确保当客户端再也不工做时,释放为这个客户端分配的资源,防止内存泄漏。所以须要一种机制使双方知道你们都在正常运行。在实现上:
WebSocket是HTML5开始提供的一种在单个 TCP 链接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,WebSocketAPI被W3C定为标准。在WebSocket API中,浏览器和服务器只须要作一个握手的动做,而后,浏览器和服务器之间就造成了一条快速通道。二者之间就直接能够数据互相传送。
因为websocket技术要说明白的话所须要的篇幅不小,因此会在以后的单独文章中介绍下websocket的使用方式,这里就不作详细的说明了。
根据以上技术的优缺点和具体业务须要,能够选择合适的技术进行应用。