原文发表于:2015-12-25,本文源于领导让研究一下comet4j这个东西后发的邮件。
comet4j
框架原理
一开始还以为这玩意儿底层是优先使用websocket来实现的,不支持的情况再定时ajax请求服务器,后来简单分析了一下前端和后台的源码,发现从头到尾都没用到websocket,也没有用到EventSource,只是在开始时与服务器通信一次,分配一个唯一ID,然后再发送一次ajax请求,服务器接收到请求后并不立即返回结果,只是暂时拿着这个连接一直等着,直到服务器有消息需要推送了才发送结果给浏览器,然后根据浏览器的支持情况分别处理,如果支持xhr的progress事件(XMLHttpRequest Level 2),就在这个事件里面不停的接收来自服务器的数据,从头到尾都在使用原来的那个连接,并没有创建新的连接,用浏览器打开这个URL可以看到进度条一直在转,页面的内容也在不停的追加,而对于不支持progress的浏览器,则直接在接收到结果后再次重新发起ajax请求,假如服务器每5秒发送一次消息给浏览器,那么浏览器每5秒都会重新发送一次xhr请求。
兼容性
这个框架的作者将前者称之为长连接,后者称之为长轮询,很显然,长轮询肯定没什么兼容性问题,长连接的话需要浏览器对XMLHttpRequest Level 2的支持,这个支持也比较好,基本上支持HTML5的现代浏览器都支持,IE要求IE9+,安卓上也普遍支持;在大麦的盒子上测试是没有任何问题的,也很实时。
实时性
支持长连接的浏览器因为一直保持这和服务器的连接,所以实时性很好,长轮询则跟循环的频率有关。
性能
由于服务器需要hold住那个连接直到有消息推送时才响应,因为长时间占用连接所以对服务器资源消耗较大,特别是当用户多的时候,而且消息推送可能也没那么频繁,浏览器必须设置足够长的超时时间,否则超时之后又要重新发起连接;
框架本身
名字起得很霸气,不仔细看还以为和log4j等同级别的高大上的开源框架,至少是老外写的,结果细查一番,发现完全就是一个个人的作品,而且还是个中国人写的的,更要命的是自从2011年发布了0.1.0版本之后就再也没有更新过了,源码还是挂在google code上的。。。
另外,代码有些地方确实写的太随便了,js的命名竟然是类似“JS.Engine.xxx”这样:
在判断浏览器是否支持XMLHttpRequest Level 2的问题上(作者称之为StreamingXHR),竟然是在后台简单的通过判断userAgent来区分的,而且版本都没管,IE则无论IE几统统认为不支持(其实IE10以上是支持的)。。。
web推送
按照浏览器的发展历程或者兼容性从前到后介绍。
1、短轮询
这几乎是所有人最容易想到的实现服务器推送的方法,就是浏览器定时主动ajax请求服务器,服务器如果有新消息就拿过来。这种方法缺点显而易见,既大量占用前后端资源,消息的推送又不及时,优点是实现简单,几乎没有兼容性可担心的。
2、长轮询
长轮询与短轮询的区别在于,如果服务器没有新消息需要推送,那么并不立即响应,而是来一个循环一直在等待,等到有新消息了再response,浏览器接收到消息后作出相应处理,然后再次发出相同请求,如此反复。相比短轮询,这种方式跟服务器的连接大大减少了,但是也还是需要频繁的连接。
3、长连接
根据我的理解,长连接可能也要分为2种:
(a)、第一种就是上面comet4j在主流浏览器上的实现方式,一个ajax请求发出去,一直不断开,服务器在不间断的response,浏览器也在不停的接收,优点上面说了,实时、连接次数少,但是占用服务器资源。
(b)、第二种长连接是使用HTML的EventSource,一般叫做Server Send Event(SSE),可以很容易的实现消息推送,但是缺点是兼容性不是很乐观,安卓上要求4.4+(如果使用Crosswalk则只需要4.0+),IE则全系列都不支持(包括edge):
4、websocket
最后一种也是终极方案当然是websocket了,优点显而易见,因为是一种全新的全双工通讯协议,完全没有http的请求响应概念,连接一旦建立就一直保持,浏览器与服务器完全平等可以互相发送数据,服务端也不需要长时间hold住那个连接,所以对服务器的资源占用也很小,缺点也很明显,也是兼容性不佳,也是要求Android4.4+(使用crosswalk则是4.0+),
总结:
以上4种方式,无论是从兼容性从高到低,还是实时性从低到高,亦或是服务器资源占用从高到低,排列顺序都是:
短轮询 -> 长轮询 -> 长连接/SSE -> websocket
Server Send Event和WebSocket都属于HTML5范畴的东西,根据目前的理解,二者都很容易实现消息推送,但是貌似前者实现起来更简单,因为前者是专门为服务器消息推送设计的,后者使用范围则更广,服务端实现上稍微复杂一点。
补充
关于comet4j,虽然这个框架不可取,但是其实现方式还是可取的,至少在普通安卓设备上没什么兼容性问题,消息推送也及时,但目前尚不知其在用户量大的情况下对服务器的压力究竟具体如何。
另外Pomelo还没来得及去了解。
2015-12-25