原文:http://yorsal.com/archives/302

随着人们对Web即时应用需求的不断上升,Server Push(推送)技术在聊天、消息提醒尤其是社交网络等方面开始兴起,成为实时应用的数据流核心。这篇日志试图探讨的便是各种适合于PHP的Push的实现方式以及其优劣。

1. 什么是Server Push

想象在聊天应用中,如果使用传统的ajax来承担消息的传入,那么一般是通过每隔一定时间拉取一次信息的方式实现,但是其实这种方式有大量查询是浪费的。聊天等Web应用更需要服务器在特定时间来主动告知前端有新的消息(Push),而不是前端每时每刻问服务器:“来消息了吗?”(Pull)。这也正是为什么这个技术常被叫做反向ajax。

其他别名:Comet,反向Ajax

2. 如何实现Push

其实所谓的推送技术也没有多么复杂,目前从大类上有3种,一种仍然建立在ajax基础上,还有一种建立在框架基础上,最后一种抛弃了传统的HTTP协议,使用Flash或者HTML5的WebSockets技术。接下来将对这三种类别产生的不同的方式进行探讨。

1) Ajax 长轮询

Ajax长轮询从本质上来说仍然是一种pull,但是实时性较高,无用请求减少很多,是一种不错的Push实现方案。不过它只减少了网络上的无谓消耗。

核心: 客户端发起一个ajax请求,服务端将请求搁置(pending)或者说挂起,直到到了超时时间(timeout)或需要推送时返回;客户端则等待ajax返回后处理数据,再发起下一个ajax请求。

优点: 兼容性较高,实现简单

缺点: 对于php这种语言来说,如果要做到实时,那么服务端就要承受大得多的压力,因为搁置到什么时候往往是不确定的,这就要php脚本每次搁置都进行一个while循环。
当然,如果服务器刷新每秒级,那尚可接受,只是实时性上退化了。

注意: 浏览器有连接数限制。我得出的结论是如果当前页面上有一个ajax请求处于等待返回状态,那么其他ajax请求都会被搁置(Chrome, Firefox已测)。如果页面有一般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

Start Using HTML5 WebSockets Today

Comet(Wikipedia)

Ajax跨域和js跨域解决方案

Jquery+php实现comet

PHP ServerPush的更多相关文章

  1. PHP ServerPush (推送) 技术的探讨

    2016年11月29日17:51:03 转自:http://www.cnblogs.com/hnrainll/archive/2013/05/07/3064874.html 需求: 我想做个会员站内通 ...

  2. PHP ServerPush <转>

    http://www.cnblogs.com/hnrainll/archive/2013/05/07/3064874.html

  3. PHP ServerPush (推送) 技术

    用来代替ajax的请求 转自:http://blog.163.com/bailin_li/blog/static/17449017920124811524364/ 需求: 我想做个会员站内通知的功能. ...

  4. PHP ServerPush (推送) 技术的探讨[整理]

    需求: 我想做个会员站内通知的功能.不想用以前的ajax查询,听说有个推技术.以下文章介绍的不错,来自转载, ============================================= ...

  5. PHP ServerPush (推送) 技术的探讨【转】

    随着人们对Web即时应用需求的不断上升,Server Push(推送)技术在聊天.消息提醒尤其是社交网络等方面开始兴起,成为实时应用的数据流核心.这篇日志试图探讨的便是各种适合于PHP的Push的实现 ...

  6. 【干货分享】前端面试知识点锦集04(Others篇)——附答案

    四.Others部分 技术类 1.http状态码有哪些?分别代表是什么意思? (1).成功2×× 成功处理了请求的状态码.200 服务器已成功处理了请求并提供了请求的网页.204 服务器成功处理了请求 ...

  7. h5面试题集合

    一.闭包的理解: 使用闭包主要是为了设计私有的方法和变量.闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露. 闭包三个特性: 1.函数嵌套函数 ; ...

  8. 使用php+swoole对client数据实时更新(下)

    上一篇提到了swoole的基本使用,现在通过几行基本的语句来实现比较复杂的逻辑操作: 先说一下业务场景.我们目前的大多数应用都是以服务端+接口+客户端的方式去协调工作的,这样的好处在于不论是处在何种终 ...

  9. 使用php+swoole对client数据实时更新(上)

    如果想对一个列表做实时的更新,传统的做法是采用轮询的方式.以web为例,通过Ajax定时请求服务端然后获取数据显示在页面.这种方式实现简单,缺点就是浪费资源. HTTP1.1新增加了对websocke ...

随机推荐

  1. (转)mongodb常用命令脚本化-自动化运维

    mongodb常用命令脚本化-自动化运维 把一些运维中常用到的mongodb命令写成shell脚本,极大的方便了维护   1 设置副本集   #!/bin/bash#mongodb 进入client ...

  2. xml_editor

    概要 该工程是用来操作xml, 目的是为了在程序中操作xml中各类节点更加简单, 下面按照 工程简介, 库内部实现, 库接口使用, xml工具使用, xpath简介 几个部分来介绍该c++库. 工程简 ...

  3. Redis源码研究--双向链表

    之前看的内容,占个位子,以后补上. ----------8月4日--------------- 双向链表这部分看的比较爽,代码写的中规中矩,心里窃喜,跟之前学的<数据结构>这本书中差不多. ...

  4. MySQL实战积累

    IFNULL(expr1,expr2)的用法:假如expr1不为NULL,则IFNULL()的返回值为   expr1; 否则其返回值为expr2. 索引:http://www.cnblogs.com ...

  5. [转]null和""以及==与equals的区别

    String str1 = null; str引用为空 String str2 = ""; str引用为空串 直接点就是null没有分配内存空间,而""分配了内 ...

  6. cadence PCB绘制步骤

    1 创建一个PCB文件  file -> new 2 创建一个板框  add -> line ,在 options 选型中选择好,板框为 长 4400mil 宽 3200 3 给PCB板框 ...

  7. linux 进程控制笔记

    进程创建 普通函数调用完成后,最多返回(return)一次,但fork/vfork会返回二次,一次返回给父进程,一次返回给子进程 父进程的返回值为子进程的进程ID,子进程的返回值为0 1.pid_t ...

  8. JAVA读取TXT文本中的数据

    现在在Demo.txt中存在数据: ABC 需要将ABC从文本文件中读取出来 代码片: import java.io.*; class FileReaderDemo { public static v ...

  9. python命令行参数处理模块 optparse 使用参考

    from optparse import OptionParser parser = OptionParser() parser.add_option( '-f', '--file', dest='f ...

  10. OGG配置

    准备安装和运行用户(操作系统用户) 建议使用oracle用户 也可以使用新建用户:但是需要做配置 必须缴入到oinstall 组 必须使用和oracle相同的profile 操作系统必须为该用户开放一 ...