一、comet简介:

comet :基于 HTTP长连接的“服务器推”技术,是一种新的 Web 应用架构。基于这种架构开发的应用中,服务器端会主动以异步的方式向客户端程序推送数据,而不需要客户端显式的发出请求。Comet 架构非常适合事件驱动的 Web 应用,以及对交互性和实时性要求很强的应用,如股票交易行情分析、聊天室和 Web 版在线游戏等。

二、comet4j功能特性

  • 推送消息广播。
  • 推送定向消息。
  • 提供连接上线前、上线、下线前、下线、发送消息等多种可处理事件。
  • 消息缓存机制,确保长轮询工作模式下不丢失消息。
  • 客户端正常下线,服务端可立即感知。
  • 客户端异常停止工作,服务端可定时检查并感知。
  • 以注册通道应用的方式,让开发者对框架功能进行扩展,实现自己的应用。

三、comet4j框架特性

  • 独立小巧,不依赖于第三方包。
  • 与应用紧密集成,无需独立应用或服务器。
  • 与Session无关的连接机制,为开发人员提供最大程度的功能可控性。
  • 面向事件编程,客户端与服务器端均为事件驱动开发模式,提供了良好的可扩展性机制。
  • 各项性能参数均可配置。
  • 支持多种主流浏览器,并支持Air应用环境。

四、comet4j实战应用

  (1)下载comet4j所需要的jar包和js文件。具体下载地址:http://code.google.com/p/comet4j/

  (2)新建web项目:如图 项目demo下载地址:http://pan.baidu.com/s/1hqsUpzI

    

   (3)在demo中可以发现,index.jsp中所用的CHANNEL必须与Comet4j.java中设置的CHANNEL相一致,在整个推送中,

     采用的是单例模式,所以开发人员不必担心它会消耗大量的内存。

   (4)comet4j开发简单,只需参考其客户端和服务端的API文档,做出你想要的推送功能应该是没有问题的。

  第二种:大家比较熟悉

一.WebSocket简单介绍
一.WebSocket简单介绍
  随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了。近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据。$ j6 s6 P/ d( K- G' m
  我们知道,传统的HTTP协议是无状态的,每次请求(request)都要由客户端(如 浏览器)主动发起,服务端进行处理后返回response结果,而服务端很难主动向客户端发送数据;这种客户端是主动方,服务端是被动方的传统Web模式 对于信息变化不频繁的Web应用来说造成的麻烦较小,而对于涉及实时信息的Web应用却带来了很大的不便,如带有即时通信、实时数据、订阅推送等功能的应 用。在WebSocket规范提出之前,开发人员若要实现这些实时性较强的功能,经常会使用折衷的解决方法:轮询(polling)和Comet技术。其实后者本质上也是一种轮询,只不过有所改进。
  轮询是最原始的实现实时Web应用的解决方案。轮询技术要求客户端以设定的时间间隔周期性地向服务端发送请求,频繁地查询是否有新的数据改动。明显地,这种方法会导致过多不必要的请求,浪费流量和服务器资源。
  Comet技术又可以分为长轮询和流技术。长轮询改进了上述的轮询技术,减小了无用的请求。它会为某些数据设定过期时间,当数据过期后才会向服务端发送请求;这种机制适合数据的改动不是特别频繁的情况。流技术通常是指客户端使用一个隐藏的窗口与服务端建立一个HTTP长连接,服务端会不断更新连接状态以保持HTTP长连接存活;这样的话,服务端就可以通过这条长连接主动将数据发送给客户端;流技术在大并发环境下,可能会考验到服务端的性能。
  这两种技术都是基于请求-应答模式,都不算是真正意义上的实时技术;它们的每一次请求、应答,都浪费了一定流量在相同的头部信息上,并且开发复杂度也较大。. C  w( i) E4 k. P, m; g
  伴随着HTML5推出的WebSocket,真正实现了Web的实时通信,使B/S模式具备了C/S模式的实时通信能力。WebSocket的工作流程是这 样的:浏览器通过javaScript向服务端发出建立WebSocket连接的请求,在WebSocket连接建立成功后,客户端和服务端就可以通过 TCP连接传输数据。因为WebSocket连接本质上是TCP连接,不需要每次传输都带上重复的头部数据,所以它的数据传输量比轮询和Comet技术小 了很多。本文不详细地介绍WebSocket规范,主要介绍下WebSocket在Java Web中的实现。# k- L0 {# i. k
  JavaEE 7中出了JSR-356:Java API for WebSocket规范。不少Web容器,如Tomcat,Nginx,Jetty等都支持WebSocket。Tomcat从7.0.27开始支持 WebSocket,从7.0.47开始支持JSR-356,下面的Demo代码也是需要部署在Tomcat7.0.47以上的版本才能运行。# W" f) D, @: u) Y0 L' ~

二、WebSocket协议介绍
 WebSocket协议是一种双向通信协议,它建立在TCP之上,同http一样通过TCP来传输数据,但是它和http最大的不同有两点:1.WebSocket是一种双向通信协议,在建立连接后,WebSocket服务器和Browser/UA都能主动的向对方发送或接收数据,就像Socket一样,不同的是WebSocket是一种建立在Web基础上的一种简单模拟Socket的协议;2.WebSocket需要通过握手连接,类似于TCP它也需要客户端和服务器端进行握手连接,连接成功后才能相互通信。简单的建立握手的时序图如下:+ h; ~; q4 `/ {
<ignore_js_op> 
握手过程:
Browser与WebSocket服务器通过TCP三次握手建立连接,如果这个建立连接失败,那么后面的过程就不会执行,Web应用程序将收到错误消息通知。
在TCP建立连接成功后,Browser/UA通过http协议传送WebSocket支持的版本号,协议的字版本号,原始地址,主机地址等等一些列字段给服务器端。
WebSocket服务器收到Browser/UA发送来的握手请求后,如果数据包数据和格式正确,客户端和服务器端的协议版本号匹配等等,就接受本次握手连接,并给出相应的数据回复,同样回复的数据包也是采用http协议传输。- s" j: [- c" o- k
Browser收到服务器回复的数据包后,如果数据包内容、格式都没有问题的话,就表示本次连接成功,触发onopen消息,此时Web开发者就可以在此时通过send接口想服务器发送数据。否则,握手连接失败,Web应用程序会收到onerror消息,并且能知道连接失败的原因。5 V, k5 ?2 l7 M( \2 b  H
' z7 g9 w, D$ O% k) U
三、Tomcat 7中的Websocket架构3 E7 s, g+ f% r% u4 Y% `
) F' S5 |4 q- W
如图所示,因为Websocket通信分为握手和数据传输两个过程,两个过程中需要用到的处理方式是不一样的,握手过程是基于HTTP 1.1基础上的,而数据传输是直接基于TCP的流传输。 ' ]4 R- C. L! S5 x; y* j
       握手过程中,在HttpServletRequest的基础上,封装了WsHttpServletRequest类,添加了对Request的失效操作函数invalidate()。而在数据通信时,接受和处理数据过程中,基于org.apache.coyote.http11.upgrade.UpgradeInbound重新封装了用于处理数据输入流的类StreamInbound,并在StreamInbound的基础上扩展生成了用于消息处理的类MessageInbound。在这两个数据处理类中均留有onData,onTextData/onBinaryData,onOpen,onClose等事件操作函数接口,这些接口将在载入的代码类中实现业务逻辑。在用于数据输出流的类WsOutbound则是封装了UpgradeOutbound对象实例,基于UpgradeOutbound对象的基础上,添加了websocket响应有关的处理逻辑。这里处理函数均为同步调用的函数,保证websocket响应的时序性。
       Tomcat中Websocket的处理流程如下:<ignore_js_op> 
接收客户端发来的握手请求,Coyote.http11连接器对socket进行解析,形成HttpServletRequest发送给Container。
Container中的相应WebsocketServlet处理请求,如不接受连接请求,则返回,如接受连接请求,则对请求作出响应,建立起客户端和服务器的socket连接。
服务器此时可以通过WsOutbound发送数据给客户端,同时通过StreamInbound监听socket。/ d3 C$ S' N4 s" m
如果接收到客户端发来的数据,则将socket数据解析成frame,判断frame类型,通过事件分发数据到不同的逻辑处理流程。
数据返回时调用WsOutbound对返回的数据进行封装处理,发送给客户端。

四、代码实现以及需求

1、项目需要,定时向所有在线用户推送一个广告或是推送一个通知之类的(比如服务器升级,请保存好手头工作之类的)。: f  |, D6 R. _0 ~3 d
' p- `, F0 Y* g4 B. g9 ]# `
2、相关环境 , Nginx、tomcat7、centos 6.5
7 }  m0 R% \$ F' u1 A
3、项目框架,springMvc 4.0.6、layer
! u- Q0 {: B2 u- e. `6 G
4、代码实现:) W  R/ N6 U/ C& L/ t3 R) a& h

WebSocketConfig:

  1. import websocket.handler.SystemWebSocketHandler;$ `, D+ H. H9 E  J7 R
  2. @Configuration
  3. @EnableWebMvc
  4. @EnableWebSocket9 Z9 l6 i" h) g4 G$ S" ^& Q
  5. public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer{6 K% ]3 U1 O# C- {% n
  6. @Override+ J+ `% d% m  |3 j6 I7 A+ u' \
  7. public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
  8. registry.addHandler(systemWebSocketHandler(),"/webSocketServer");4 H0 k% Y9 o8 `/ L6 y7 W/ B' n
  9. registry.addHandler(systemWebSocketHandler(),"/sockjs/webSocketServer");
  10. }
  11. @Bean' \6 ], m4 }% f' E' U" \
  12. public WebSocketHandler systemWebSocketHandler(){
  13. return new SystemWebSocketHandler();: S- |& U# }/ C" G$ v5 a
  14. }
  15. }

复制代码

SystemWebSocketHandler:

  1. public class SystemWebSocketHandler extends  TextWebSocketHandler {
  2. % }- u" Q6 D# F# P# w; P2 d
  3. private static final ArrayList<WebSocketSession> users = new ArrayList<WebSocketSession>();;4 ?+ A. V$ Y/ }& h
  4. x- y) r8 U/ n; M+ Y$ l
  5. public void afterConnectionEstablished(WebSocketSession session) throws Exception {
  6. System.out.println("ConnectionEstablished");
  7. users.add(session);% X7 y- v( \* u! ^
  8. System.out.println("当前用户"+users.size());
  9. }! k5 d' v$ [3 b, u5 l, z
  10. /**( b# S3 }0 }* ?; x* ^
  11. * 在UI在用js调用websocket.send()时候,会调用该方法
  12. * @Author    张志朋7 f& A# K4 g8 X. z- |) S3 K
  13. * @param session
  14. * @param message- n) Q; i2 ?5 Y, d4 m
  15. * @throws Exception
  16. * @Date    2016年3月4日
  17. * 更新日志& n. c% Q; Y# ]
  18. * 2016年3月4日 张志朋  首次创建
  19. *
  20. */
  21. @Override
  22. protected void handleTextMessage(WebSocketSession session,5 l. }, a5 j4 W8 j, U% x
  23. TextMessage message) throws Exception {( ~( P! W; T. H$ G* U8 W
  24. super.handleTextMessage(session, message);
  25. sendMessageToUsers(session,message);
  26. }
  27. @Override9 m3 d( B# t% r" z0 e
  28. public void handleTransportError(WebSocketSession session, Throwable exception) throws IOException {
  29. if(session.isOpen()){% x  j0 I! c0 S5 Y
  30. session.close();
  31. }
  32. users.remove(session);5 @6 y! F$ k, D- s/ N9 v5 V
  33. }) m1 |, z8 r$ ]0 B
  34. @Override
  35. public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {& u* X6 C/ N* }. ?. e2 w
  36. users.remove(session);, o, ?0 A. J7 o2 z6 `' b
  37. }8 p# X, ?0 m7 `+ J
  38. % V3 r% E, m; }1 ]5 D
  39. @Override) A1 [; K/ }6 D% [! ^
  40. public boolean supportsPartialMessages() {& Y' N& U! ~* z( m! h* {. f
  41. return false;
  42. }  t9 ]* K% z7 C( C# E- |- F+ i
  43. /**! Z3 L$ S' Q. \1 G- p: I3 {. D1 E9 W
  44. * 给所有在线用户发送消息
  45. * @Author    张志朋
  46. * @param message  void* Y) `$ f0 T4 M+ b6 q8 X2 p5 F
  47. * @Date    2016年3月4日
  48. * 更新日志1 q% I4 Y  E. @. Z# H- E
  49. * 2016年3月4日 张志朋  首次创建
  50. *5 V5 u3 a+ G5 r# P+ f, Y/ {
  51. */2 H6 z3 A/ m4 ?0 h( ~5 o% X
  52. public void sendMessageToUsers(WebSocketSession session,TextMessage message) {/ l  f: d! @" [% g% ]% j! ?
  53. for (WebSocketSession user : users) {
  54. try {; K! [3 k) B! }. v
  55. if (user.isOpen()) {
  56. user.sendMessage(message);, ?$ r7 A% ?  n1 ]. [7 @$ j
  57. }
  58. } catch (IOException e) {
  59. e.printStackTrace();: c1 t* |1 j$ I% o4 t8 H
  60. }% ]6 X6 _9 e) z, `) j% `! H2 N
  61. }
  62. }2 ^# o( i  `( h' Z7 L
  63. }

复制代码

信息输入 index.html:- \0 z& k; w5 d$ U1 ~( ~* T

  1. <html xmlns="http://www.w3.org/1999/xhtml">
  2. <head>7 a8 f3 O5 v; b# g3 B: ^
  3. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  4. <title>请输入任意消息</title>
  5. <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>7 @( l1 e# @) X
  6. <script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
  7. <script type="text/javascript">
  8. var ws = null;
  9. $(function () {
  10. if ('WebSocket' in window) {
  11. ws = new WebSocket('ws://127.0.0.1:8080/webSocketServer'); 5 S+ j  {# E8 F2 o( ^2 L8 A: f: F" d
  12. }
  13. else if ('MozWebSocket' in window) {$ j1 }4 R% _- _& z3 F
  14. ws = new MozWebSocket("ws://127.0.0.1:8080/webSocketServer");
  15. }
  16. else {
  17. ws = new SockJS("ws://127.0.0.1:8080/webSocketServer");+ P& w: ?* O' _/ [6 e' t, {0 F
  18. }. v- m! b& `; f0 P3 C5 t
  19. ws.onopen = function () {/ B$ e  Q$ b) D
  20. / K$ l6 b6 S7 m2 j' A; m/ j
  21. };
  22. ws.onmessage = function (event) {3 O! h. f! h$ m7 Q* M: s2 Y
  23. " V1 p. q# `/ K
  24. };
  25. ws.onclose = function (event) {
  26. 6 D7 _" h$ ?, Y
  27. };! e8 }; o, ^! }( o, Q2 r6 \+ z. o( M
  28. });
  29. function stop(){+ x8 U6 s7 p. c( U; G0 i
  30. var message = $("#message").val();$ w. u: E" p5 `! I
  31. ws.send(message);6 G  u8 P3 a( O  |5 W8 g8 [
  32. }
  33. </script>; u% \/ M8 b7 O0 D5 t5 h" _
  34. </head>9 U  H/ y, ^' M- f# N
  35. <body class="keBody">  X0 D& H9 u5 d( e0 C: F/ `: R) Q
  36. 请输入提示信息: <textarea id="message"></textarea><br />
  37. <input type="button"  value="开始" />
  38. </body>5 ?% i; h6 ?2 b4 M. [/ f/ b+ j
  39. </html>

复制代码

6 q0 F$ y& l  t8 y" a( U( I& n
webSocket.js  用于导入项目。

  1. document.write("<script language=javascript src='http://127.0.0.1:8080/js/jquery-1.10.2.min.js'></script>");
  2. document.write("<script language=javascript src='http://127.0.0.1:8080/layer/layer.js'></script>");; Z" F* y3 X" ^* A6 {! Q9 @( M
  3. document.write("<script language=javascript src='http://cdn.sockjs.org/sockjs-0.3.min.js'></script>");
  4. var ws = null;0 K' _) I, _( z: |( t$ b. g
  5. var basePath = "ws://127.0.0.1:8080/";9 i2 {9 p1 H' T9 b' U
  6. if ('WebSocket' in window) {# w8 N+ p" v, F/ v% K
  7. ws = new WebSocket(basePath+'webSocketServer'); 4 q. Z! u% i( I' }. t) o1 |
  8. }
  9. else if ('MozWebSocket' in window) {
  10. ws = new MozWebSocket(basePath+"webSocketServer");0 }9 y3 Y9 T% m3 ?/ [; b; Y7 p
  11. }
  12. else {, p. l% Z1 e6 t/ D. m8 q
  13. ws = new SockJS(basePath+"sockjs/webSocketServer");
  14. }" C8 y7 f/ C. }# [& W# G
  15. ws.onopen = function () {
  16. + J/ T- r4 L" d) [' b9 L2 T
  17. };3 R6 @8 v! b1 K# O
  18. ws.onmessage = function (event) {
  19. pop(event.data);- C6 d! {5 ^1 q5 a
  20. };
  21. ws.onclose = function (event) {
  22. ws.close();1 \8 x$ [- o2 \/ Z
  23. };
  24. //提示信息
  25. function pop(message){. ]  Q% }1 `; B
  26. layer.alert(message);* d4 H2 b0 }) I( j, ~, k
  27. }

复制代码

9 \; ^. D: M; Y% o5 B2 [
5、在项目头部引入% D0 _; w8 y) {( C: n6 e$ K
<script language=javascript src='http://127.0.0.1:8080/webSocket.js '></script>

这时查看后台 会有以下信息 说明 引入成功。# T; \, y% L  c+ d1 ~% U
<ignore_js_op>

然后在打开页面 index.html 输入以下内容 点击开始即可。/ d% h3 B% d: \9 E
<ignore_js_op>

如果在网站出现一下提示说明配置成功,这时候所有网站登录用户都可以收到此信息。, N5 ^, y) H4 C2 ]3 c* }
<ignore_js_op>

WEB消息推送-comet4j的更多相关文章

  1. WEB消息推送-框架篇

    WEB消息推送-comet4j 一.comet简介: comet :基于 HTTP长连接的“服务器推”技术,是一种新的 Web 应用架构.基于这种架构开发的应用中,服务器端会主动以异步的方式向客户端程 ...

  2. 实现web消息推送的技术和采用长轮询corundumstudio介绍

    实时消息的推送,PC端的推送技术可以使用socket建立一个长连接来实现.传统的web服务都是客户端发出请求,服务端给出响应.但是现在直观的要求是允许特定时间内在没有客户端发起请求的情况下服务端主动推 ...

  3. web消息推送-goesay

    原文:http://www.upwqy.com/details/22.html 1 GoEasy简介: GoEasy - Web实时消息推送服务专家 最简单的方式将消息从服务器端推送至客户端 最简单的 ...

  4. WEB消息推送-原理篇

    这篇文章主要讲述B/S架构中服务器“推送”消息给浏览器.内容涉及ajax论询(polling),comet(streaming,long polling).后面会附上源代码. 最近在工作有这么一个需求 ...

  5. SSM项目使用GoEasy 实现web消息推送服务

      一.背景 之前项目需要做一个推送功能,最开始我用websocket实现我的功能.使用websocket的好处是免费自主开发,但是有几个问题:1)浏览器的兼容问题,尤其是低版本的ie:2)因为是推送 ...

  6. web消息推送的各种解决办法

    摘要 在各种BS架构的应用程序中,往往都希望服务端能够主动地向客户端推送各种消息,以达到类似于邮件.消息.待办事项等通知. 往BS架构本身存在的问题就是,服务器一直采用的是一问一答的机制.这就意味着如 ...

  7. Web消息推送框架windows部署实践

    一.官方下载地址:https://www.workerman.net/web-sender 二.解压至任意目录下,双击start_for_win.bat,效果如下图: 三.打开Chrome浏览器访问: ...

  8. 使用SuperWebSocket实现Web消息推送

    在大部分Web系统中,我们可能遇到需要向客户端推送消息的需求.SuperWebSocket第三方库能让我们轻松的完成任务.SuperWebSocket第三方库可以从网上下载,不过通过Visual St ...

  9. 关于php使用基于socket Web消息推送(未完)

    转:http://blog.csdn.net/young_phper/article/details/52441143 http://www.workerman.net/ http://blog.cs ...

随机推荐

  1. Cryptography I 学习笔记 --- 数论简介

    0. Zn代表{0,1....n-1}的集合 1. 模运算符合交换律结合律 2. gcd(greatest common divisor),可以由扩展欧几里得算法快速得到. 3. 模逆(modular ...

  2. c# redis 利用锁(StackExchange.Redis LockTake)来保证数据在高并发情况下的正确性

    之前有写过一篇介绍c#操作redis的文章 http://www.cnblogs.com/axel10/p/8459434.html ,这篇文章中的案例使用了StringIncrement来实现了高并 ...

  3. CodeForces - 361D Levko and Array

    Discription Levko has an array that consists of integers: a1, a2, ... , an. But he doesn’t like this ...

  4. noip2017集训测试赛(四)Problem A: fibonacci

    题目大意 给你一个序列\(a_1, a_2, ..., a_n\). 我们令函数\(f(n)\)表示斐波那契数列第\(n\)项的值. 总共\(m\)个操作, 分为以下两种: 将\(x \in [L, ...

  5. cocos3.7.1 mac 创建项目

    cocos2d-x-3.7/tools/cocos2d-console/bin目录下,输入命令: ./cocos.py new HelloWorldDemo -p com.coco2dx.org -l ...

  6. 关于<textarea>的内容中换行的表示方法

    <textarea>sdfsdfsffsd fer</textarea>

  7. ALBB 找公共最长连续字母序列的长度

    问题描写叙述 给定一个 query 和一个 text .均由小写字母组成.要求在 text 中找出以相同的顺序连续出如今 query 中的最长连续字母序列的长度. 比如, query为"ac ...

  8. Ambient Occulution

    SSAO HDAO normal pair 求一个谷 SAO 重建normal HBAO input depth,normal 这几个都是screen space的ao

  9. 2016.7.14 如何在浏览器中查看jsp文件

    参考资料: http://jingyan.baidu.com/article/ed15cb1b10f1241be36981ab.html 1.复制jsp文件地址 2.写在浏览器里 E:/lyh/tas ...

  10. PropertyGrid—隐藏某些Public属性

    1.定义一个继承ControlDesigner 的类 public class MyControlDesigner:System.Windows.Forms.Design.ControlDesigne ...