Pushlet之消息通知- 实现服务器端推送技术

来源:互联网 发布:自助域名绑定如何实现 编辑:程序博客网 时间:2024/05/15 10:39

Pushlet 是一个开源的 Comet 框架,在设计上有很多值得借鉴的地方,对于开发轻量级的 Comet 应用很有参考价值。

观察者模型

Pushlet 使用了观察者模型:客户端发送请求,订阅感兴趣的事件;服务器端为每个客户端分配一个会话 ID 作为标记,事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。

客户端 JavaScript 库

pushlet 提供了基于 AJAX 的 JavaScript 库文件用于实现长轮询方式的“服务器推”;还提供了基于 iframe 的 JavaScript 库文件用于实现流方式的“服务器推”。

JavaScript 库做了很多封装工作:

  1. 定义客户端的通信状态:STATE_ERRORSTATE_ABORTSTATE_NULLSTATE_READYSTATE_JOINEDSTATE_LISTENING
  2. 保存服务器分配的会话 ID,在建立连接之后的每次请求中会附上会话 ID 表明身份;
  3. 提供了 join()leave()subscribe()、 unsubsribe()listen() 等 API 供页面调用;
  4. 提供了处理响应的 JavaScript 函数接口 onData()onEvent()

网页可以很方便地使用这两个 JavaScript 库文件封装的 API 与服务器进行通信。

客户端与服务器端通信信息格式

pushlet 定义了一套客户与服务器通信的信息格式,使用 XML 格式。定义了客户端发送请求的类型:joinleavesubscribeunsubscribelistenrefresh;以及响应的事件类型:datajoin_acklisten_ackrefreshheartbeaterrorabortsubscribe_ackunsubscribe_ack

服务器端事件队列管理

pushlet 在服务器端使用 Java Servlet 实现,其数据结构的设计框架仍可适用于 PHP、C 编写的后台客户端。

Pushlet 支持客户端自己选择使用流、拉(长轮询)、轮询方式。服务器端根据客户选择的方式在读取事件队列(fetchEvents)时进行不同的处理。“轮询”模式下 fetchEvents() 会马上返回。”流“和”拉“模式使用阻塞的方式读事件,如果超时,会发给客户端发送一个没有新信息收到的“heartbeat“事件,如果是“拉”模式,会把“heartbeat”与“refresh”事件一起传给客户端,通知客户端重新发出请求、建立连接。

客户服务器之间的会话管理

服务端在客户端发送 join 请求时,会为客户端分配一个会话 ID, 并传给客户端,然后客户端就通过此会话 ID 标明身份发出subscribe 和 listen 请求。服务器端会为每个会话维护一个订阅的主题集合、事件队列。

服务器端的事件源会把新产生的事件以多播的方式发送到每个会话(即订阅者)的事件队列里。

官网: http://www.pushlets.com/



根据需要设计了一个简单的消息通知系统,使用pushlet实现。如有错误,欢迎指正,非常感谢。 


第一步 

将pushlet.jar放到工程的lib目录中,将pushlet-2.0.4\webapps\pushlet\lib\js-pushlet-client.js放到网页能访问的目录,将pushlet-2.0.4\webapps\pushlet\WEB-INF\classes\pushlet.properties和pushlet-2.0.4\webapps\pushlet\WEB-INF\classes\sources.properties拷贝到工程目录的classes目录下。 

第二步 

使用pushlets在网页客户端中配置非常简单 

在网中页面引用如下代码 
Java代码 
  1. <script type="text/javascript" src="../../lib/ajax-pushlet-client.js">  
  2. </script>  
  3.   
  4. <script type="text/javascript">  
  5.         //可以设置debug为true,会在新标签页中打印debug信息,调试的时候非常有用。  
  6.     PL.setDebug(false);  
  7.   
  8.     // Pushlet Event Callback from Server  
  9.         //回调  
  10.     function onEvent(event) {  
  11.         pr(event.toString());  
  12.     }  
  13.          
  14.         //订阅topic  
  15.     function joinListen() {  
  16.         pr('joinListen...');  
  17.         PL.joinListen('/pushlet/ping');  
  18.     }  
  19.         //取消订阅  
  20.     function leave() {  
  21.         pr('leaving...');  
  22.         PL.leave();  
  23.     }  
  24.   
  25.     // 打印信息  
  26.     function pr(aString) {  
  27.         document.disp.event.value = aString;  
  28.     }  
  29.   
  30.     //-->  
  31.     </script>  


第三步 

在工程的web.xml中添加配置如下 

Java代码 
  1. <!-- Define the pushlet servlet -->  
  2.     <servlet>  
  3.         <servlet-name>pushlet</servlet-name>  
  4.         <servlet-class>nl.justobjects.pushlet.servlet.Pushlet</servlet-class>  
  5.         <load-on-startup>1</load-on-startup>  
  6.     </servlet>  
  7.   
  8.     <!-- Define the Servlet Mappings. -->  
  9.   
  10.     <!-- The pushlet -->  
  11.     <servlet-mapping>  
  12.         <servlet-name>pushlet</servlet-name>  
  13.         <url-pattern>/js/pushlet.srv</url-pattern>  
  14.     </servlet-mapping>  

其中url-pattern跟前面ajax-pushlet-client.js放置的目录有关,需要根据自己的项目路径调整。 

第四步 
服务器端实现pushlets有两种方式,第一种使用eventpullsource,需要实现包含一个继承了EventPullSource的内部静态类,如下面代码中的EncodeJobQuery。 
Java代码 
  1. public class EncodeJobQuery {  
  2.   
  3.     public static class EncodeJobEventPullSource extends EventPullSource {  
  4.         Logger log = Logger.getLogger(getClass());  
  5.         @Autowired  
  6.         PvmsEncodeMessageManager encodeMessageManager;  
  7.           
  8.         @Override  
  9.         protected long getSleepTime() {  
  10.             return 5000l;  
  11.         }  
  12.   
  13.         @Override  
  14.         protected Event pullEvent() {  
  15.                         //参数是subject,与js中的subject相同  
  16.             Event event = Event.createDataEvent("/pushlet/ping");  
  17.             event.setField("msg""encoding....");  
  18.             return event;  
  19.         }  
  20.     }  
  21. }  

同时要在classes/sources.properties文件中增加一个行。 
Java代码 
  1. source7=cn.com.people.tv.pvms.encode.EncodeJobQuery$EncodeJobEventPullSource  


第二种方法是在程序中调用Dispatcher.getInstance().multicast(event),除了multicast还有其他两种方法用来发送消息。 
Java代码 
  1. String subject = "/pushlet/ping"  
  2. Event event = Event.createDataEvent(subject);  
  3.         event.setField("msg""ping.....");  
  4. PvmsEncodeMessage.MSG_MESSAGE_COUNT);  
  5.         Dispatcher.getInstance().multicast(event);  


总结: 
在使用的过程中遇到了若干问题 

1.怎么实现根据用户来推送消息 
我在实现的时候为不同的用户定义不同的topic,根据用户id来区分。看了文档介绍,说可以绑定pushlet的session,没研究明白具体怎么操作。我的实现方式缺点是,如果服务器重启或者消息发送失败导致pushlet的session关闭,那么后续的消息就没办法发送给用户。 

2.发送离线消息 
我把消息存在服务器,只用pushlet来发送当前的消息数量。比如在用户登录后,发送给用户一条消息告诉用户有多少条未读消息,用户可以手动标记消息为已读或者删除消息。
0 0
原创粉丝点击