随着人们对Web即时应用需求的不断上升,Server Push(推送)技术在聊天、消息提醒尤为是社交网络等方面开始兴起,成为实时应用的数据流核心。这篇日志试图探讨的即是各类适合于PHP的Push的实现方式以及其优劣。 javascript
1. 什么是Server Push php
想象在聊天应用中,若是使用传统的ajax来承担消息的传入,那么通常是经过每隔必定时间拉取一次信息的方式实现,可是其实这种方式有大量查询是浪费的。聊天等Web应用更须要服务器在特定时间来主动告知前端有新的消息(Push),而不是前端每时每刻问服务器:“来消息了吗?”(Pull)。这也正是为何这个技术常被叫作反向ajax。 html
其余别名:Comet,反向Ajax 前端
2. 如何实现Push html5
其实所谓的推送技术也没有多么复杂,目前从大类上有3种,一种仍然创建在ajax基础上,还有一种创建在框架基础上,最后一种抛弃了传统的HTTP协议,使用Flash或者HTML5的WebSockets技术。接下来将对这三种类别产生的不一样的方式进行探讨。 java
1) Ajax 长轮询 node
Ajax长轮询从本质上来讲仍然是一种pull,可是实时性较高,无用请求减小不少,是一种不错的Push实现方案。不过它只减小了网络上的无谓消耗。 web
核心: 客户端发起一个ajax请求,服务端将请求搁置(pending)或者说挂起,直到到了超时时间(timeout)或须要推送时返回;客户端则等待ajax返回后处理数据,再发起下一个ajax请求。 ajax
优势: 兼容性较高,实现简单 跨域
缺点: 对于php这种语言来讲,若是要作到实时,那么服务端就要承受大得多的压力,由于搁置到何时每每是不肯定的,这就要php脚本每次搁置都进行一个while循环。
固然,若是服务器刷新每秒级,那尚可接受,只是实时性上退化了。
注意: 浏览器有链接数限制。我得出的结论是若是当前页面上有一个ajax请求处于等待返回状态,那么其余ajax请求都会被搁置(Chrome, Firefox已测)。彷佛跟页面标记有关,一个规范的HTML能够同时有多个请求。若是页面有通常ajax需求怎么办?解决方法是开个框架,框架中使在另外一个域名下进行Comet长轮询,须要注意跨域问题。
PHP实现: Jquery+php实现comet
相关: Ajax跨域和js跨域解决方案
2) Frame 长链接
受到ajax启发,出现了框架下的长链接。
核心: Frame中发起一个普通请求,服务器将其搁置;须要推送时输出直接执行
脚本,而后继续保持链接。若是担忧超时问题能够改为框架论询。
优势: 与1同样具备高兼容特性
缺点: 最大的问题是若是框架在载入,那么浏览器就好一直显示“载入中”,这就弱爆了(解决方法参见文末的相关阅读资源)。一样服务器也要能hold住大量循环……另外,是否有同域链接限制没测试。
3) Flash/HTML5 WebSockets
用flash来发起WebSockets,秒杀前面一切问题。
优势: 标准化, RealTime, Push
缺点: 服务器须要能应对WebSockets;还有若是既没有Flash又不支持HTML5的怎么办?
PHP实现: Start Using HTML5 WebSockets Today
6) 使用兼容封装层(socket.io)
以上每种方法都有优劣,那么终极解决方案即是合在一块儿!能WebSockets时候就WebSockets,不支持HTML5特性就退化到Flash,没有Flash则退化到Ajax长轮询。这也是个人Rainbowfish所采用的方式。
优势: 高度封装,编写很是容易,几乎不须要关心如何去实现的。实时,超低负载,高并发。
缺点: 其实算不上缺点,socket.io的服务器端要求是node.js,而不是php。
我的见解: 若是你是独立主机,能运行程序,那么socket.io配合node.js是个很是高效的选择。为何呢?由于它还能够避免php的服务端高负载。
Rainbowfish的消息系统经过这种方式实现: 全部客户端都经过socket.io挂在nodejs服务器上(注意: 只是挂着,不须要任何循环,由于它是事件驱动的);须要推送消息了,服务器就与nodejs通讯(好比访问某个地址来实现),告诉它推送什么消息到哪里;nodejs收到推送信号后,则经过socket.io实时传输数据给浏览器。这个其实也是一条单向的路,由于nodejs服务器不具有与php通讯的能力,实际上也不须要,网页上直接连php就能够了。
3. 结束语
事实上,第一个方法(Ajax Long Pull)是一个不错的方法,只是若是使用php完成的话服务器负载上有点大,但这实际上是通病;而最后列举的socket.io方案彻底避免了这个问题,由于它属于另外一种架构,而且这种组合也能够配合几乎全部的脚本语言实现push。
对于实时性要求很是高的应用,或许使用php实现实时部分并非一个好的选择,将会面临很是大的服务器负载(能够经过编写支持等待事件的扩展来解决这个问题);若是只是消息提示等,则能够调整服务器上刷新的间隔下降到秒的级别,负载尚可接受。不过不管哪一种用途,配合那些非阻塞语言或许才是最好的选择。
4. 相关阅读
How to implement COMET with PHP