一、comet基本概念
1.comet是一个用于描述客户端和服务器之间交互的术语,即使用长期保持的http连接来在连接保持畅通的情况下支持客户端和服务器间的事件驱动的通信。
2.传统的web系统的工作流程是客户端发出请求,服务器端进行响应,而comet则是在现有技术的基础上,实现服务器数据、事件等快速push到客户端,所以会出现一个术语”服务器推“技术。
二、push实现方式
1.原理:
利用jsp/servel技术,在不关闭http流的情况下push数据到客户端浏览器;
2.实现:
基于ajax的长轮询(long-polling)方式
ajax的出现使得javascript可以调用xmlhttprequest对象发出http请求,javascript响应处理函数根据服务器返回的信息对html页面的显示进行更新。使用ajax实现“服务器推”与传统的ajax应用不同之处在于:
1)、服务器端会阻塞请求直到有数据传递或超时才返回。
2)、客户端 javascript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。
3)、当客户端处理接收的数据、重新建立连接时,服务器端可能有新的数据到达;这些信息会被服务器端保存直到客户端重 新建立连接,客户端会一次把当前服务器端所有的信息取回。
Pushlet实例
一、首先建立一个web工程pushlet,将pushlet.jar放到lib目录中,引入到工程。并且将pushlet.properties和sources.properties两个文件拷贝到WEB-INF目录中去。工程的目录结构如图示
我们一般只需要对sources.properties进行修改即可,创建的消息源必须在这个文件中进行配置。消息源需要实现EventSource接口
二、配置web.xml文件
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- 注意,缺省不需要修改<url-pattern>/pushlet.srv</url-pattern>,如果修改, 需要在对应的js文件中也要修改。pushlt缺省就是通过pushlet.srv触发servlet的。 --> <servlet> <servlet-name>pushlet</servlet-name> <servlet-class> nl.justobjects.pushlet.servlet.Pushlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>pushlet</servlet-name> <url-pattern>/pushlet.srv</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
三、看一下index.jsp这个文件的内容
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>HelloWorld</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <script type="text/javascript" src="ajax-pushlet-client.js"></script> <script type="text/javascript"> //对pushlet的初始化,触发web.xml中的servlet。 PL._init(); //这里的监听的主题,必须在sources.properties中配置的对象中声明这个主题。 //sources.properties配置着事件源(EventSources),在服务器启动时会自动激活。 //可以通过服务器的启动记录查看得到。可以将这个文件放到WEB-INF目录下面或者classess目录下面都可以。 PL.joinListen('/linjiqin/hw'); function onData(event) { alert(event.get("hw")); } </script> </head> <body> </body> </html>
四、修改sources.properties文件
source1=nl.justobjects.pushlet.test.TestEventPullSources$TemperatureEventPullSource source2=nl.justobjects.pushlet.test.TestEventPullSources$SystemStatusEventPullSource source3=nl.justobjects.pushlet.test.TestEventPullSources$PushletStatusEventPullSource source4=nl.justobjects.pushlet.test.TestEventPullSources$AEXStocksEventPullSource source5=nl.justobjects.pushlet.test.TestEventPullSources$WebPresentationEventPullSource source6=nl.justobjects.pushlet.test.TestEventPullSources$PingEventPullSource #source1~source6是系统缺省自带的,source7是我自己配置的,并且在index.jsp中的脚本中, #配置的/linjiqin/hw是和这儿是对应的。具体是这样的。HwPlushlet是com.ljq.test.HelloWorldPlushlet对象的一个内部类, #并且继承EventPullSource接口。 source7=com.ljq.test.HelloWorldPlushlet
五、核心代码HelloWorldPlushlet
package com.ljq.test; import java.io.Serializable; import nl.justobjects.pushlet.core.Event; import nl.justobjects.pushlet.core.EventPullSource; @SuppressWarnings("serial") public class HelloWorldPlushlet extends EventPullSource implements Serializable { /** * 设置休眠时间 */ @Override protected long getSleepTime() { return 1000; } /** * 创建事件 * * 业务部分写在pullEvent()方法中,这个方法会被定时调用。 */ @Override protected Event pullEvent() { Event event = Event.createDataEvent("/linjiqin/hw"); event.setField("hw", "HelloWorld!!!!"); return event; } }
这样这个基本的例子就OK了,运行一下,看看吧。
访问http://localhost:8083/pushletprj 会定时弹出alert窗口,窗口的内容如下图:
如果这个页面关闭了,服务器会自动取消订阅,和移除对应的session信息。下面是我关闭页面后,服务器端的输出信息,如图:
在这里讲解一下关于开源框架Pushlet中的定点推送消息和与浏览器参数交互
通过上面的方法我就可以完成点对点的网页版本的聊天软件了,当然需要达到上面的要求我们这里需要对Pushlet的源码进行改进。
首先,我这里就讲述Pushlet的入门配置,默认大家是了解Pushlet框架的。
1. 与浏览器参数交互
需要定位一个客户端就必须要给这个客户设置一个唯一的key值,我这里就叫它为clientid,当然也有朋友会说,我使用Pushlet中每个Session的id来作为clientid,这样当然是可以的,但为了便于管理我们一般会生成自己的clientid来进行操作,我在这里要做的就是使用自己生成的clientid来替换Pushlet自己生成的Sesssion的id。
在Pushlet初始化去监听一个事件的时候我们是没有办法传递参数的,这里我就需要改动一下ajax-pushlet-client.js中的代码,来满足我们的需求,添加参数数组的定义,并且修改_doRequest函数如下代码:
- var PL = {
- NV_P_FORMAT: 'p_format=xml-strict',
- NV_P_MODE: 'p_mode=pull',
- pushletURL: null,
- webRoot: null,
- sessionId: null,
- parameters: new Array(new Array),// 对参数数组的定义
- STATE_ERROR: -2,
- STATE_ABORT: -1,
- STATE_NULL: 1,
- STATE_READY: 2,
- STATE_JOINED: 3,
- STATE_LISTENING: 3,
- state: 1,
- ......
- _doRequest: function(anEvent, aQuery) {
- ......
- if(PL.parameters.length > 0) {
- for (var i = 0; i < PL.parameters.length; i++) {
- var para = PL.parameters[i];
- url += "&" + para.name + "=" + para.value;
- }
- }
- ......
- },
加入代码后的_doRequest函数如下:
- _doRequest: function(anEvent, aQuery) {
- ......
- // Construct base URL for GET
- var url = PL.pushletURL + '?p_event=' + anEvent;
- // Optionally attach query string
- if (aQuery) {
- url = url + '&' + aQuery;
- }
- // Optionally attach session id
- if (PL.sessionId != null) {
- url = url + '&p_id=' + PL.sessionId;
- if (anEvent == 'p_leave') {
- PL.sessionId = null;
- }
- }
- if(PL.parameters.length > 0) {
- for (var i = 0; i < PL.parameters.length; i++) {
- var para = PL.parameters[i];
- url += "&" + para.name + "=" + para.value;
- }
- }
- PL.debug('_doRequest', url);
- PL._getXML(url, PL._onResponse);
- },
代码改好后就可以这样写我的Pushlet初始化代码了,传入我们所需要的clientid给服务器,代码如下:
- var initPushlet = function() {
- PL._init();
- PL.parameters.push({"clientid":"servicekey", "value":"4214f0c0da6760a9e95e3c164998ac06"});
- PL.joinListen('/conversation');
- };
那么,客户端把参数传过来了服务端要怎么接收它呢?这就就需要修改一下Pushlet的java源码,首先我们修改nl.justobjects.pushlet.core.SessionManager中的createSession方法,如下:
- /**
- * Create new Session (but add later).
- */
- public Session createSession(Event anEvent) throws PushletException {
- // Trivial
- return Session.create(anEvent);
- }
再修改nl.justobjects.pushlet.core.Session中的create方法,如下:
- public static Session create(Event anEvent) throws PushletException {
- Session session;
- try {
- session = (Session) Config.getClass(SESSION_CLASS, "nl.justobjects.pushlet.core.Session").newInstance();
- } catch (Throwable t) {
- throw new PushletException("Cannot instantiate Session from config", t);
- }
- // get clientid
- session.id = anEvent.getField("clientid");
- session.controller = Controller.create(session);
- session.subscriber = Subscriber.create(session);
- session.event = anEvent;
- return session;
- }
上面就完成了SessionId的转变。
如果我们要完成一个点对点聊天的话客户端和服务器通信当然是必不可少,具体怎么向服务端发消息呢?在这里我使用里Pushlet的js中的p_publish()方法,示例代码如下:
- p_publish('answer','msg',encodeURIComponent('你好吗?'),'clientid','ce8954e8557fa9db8c1b2d6774e471a6');
上面方法第一个参数是:执行的操作命令command,后面是都是传给服务器的参数,是以一个参数名+参数值的形式。参数值如果存在中文的话需要使用encodeURIComponent()方法来进行编码再传输。
在服务端我们要接收这一个客户端发过来的消息并进行处理,我需要怎么接收它呢?就需要在nl.justobjects.pushlet.core.Controller这个类中的doCommand()方法中进行处理了,找到这个方法中的eventType.equals(Protocol.E_PUBLISH)判断内,并加入自己的处理代码,代码如下:
- public void doCommand(Command aCommand) {
- try {
- ......
- } else if (eventType.equals(Protocol.E_PUBLISH)) {
- // Publish event
- doPublish(aCommand);
- // get command
- System.out.println(aCommand.reqEvent.getField("p_subject"));
- // get clientid
- System.out.println(aCommand.reqEvent.getField("clientid"));
- // get msg
- System.out.println(new String(aCommand.reqEvent.getField("msg").getBytes("ISO8859-1"), "UTF-8"));
- } else if (eventType.equals(Protocol.E_LISTEN)) {
- // Listen to pushed events
- doListen(aCommand);
- }
- ......
- } catch (Throwable t) {
- warn("Exception in doCommand(): " + t);
- t.printStackTrace();
- }
- }
aCommand.reqEvent.getField("p_subject"))就可以获得客户端传过来的command命令,aCommand.reqEvent.getField("参数名")来获取传过来参数。当然在正常的开发中,所用到的命令会很多,我们可以把每一个命令做成一个个子类去实现,完成不同的需求。至于怎么将消息发送给客户端,将在下面的定点推送消息中讲解。
2. 定点推送消息
上面已经讲述了每个客户端都会存在一个clientid,这个clientid可以定位每一个客户端,那么既然我们需要向某一个客户端推送消息,那必然要知道这个客户端的clientid,这里我建议开发者自己写一个管理器用于管理连接上来的客户端,用于保存这些客户端的信息。如果需要开发聊天程序的话则需要写一个聊天会话管理器,用于管理一对对的聊天会话Session。
言归正传,我们接着1内容中的最后说,当我们在doCommand()方法中获得了某一个客户端传过来的消息时,我们可能需要做的是将处理的结果返回给它,或将它的消息发给另外一个客户端,至于怎么做呢?我们直接看代码,还是上面的代码加入了些内容如下:
- public void doCommand(Command aCommand) {
- try {
- ......
- } else if (eventType.equals(Protocol.E_PUBLISH)) {
- // Publish event
- doPublish(aCommand);
- // get command
- System.out.println(aCommand.reqEvent.getField("p_subject"));
- // get clientid
- System.out.println(aCommand.reqEvent.getField("clientid"));
- // get msg
- System.out.println(new String(aCommand.reqEvent.getField("msg").getBytes("ISO8859-1"), "UTF-8"));
- // 发送给其他客户端
- Event event = Event.createDataEvent("/conversation"); // 监听的事件
- event.setField("cmd", "say");
- event.setField("code", 100);
- event.setField("msg", new String(aCommand.reqEvent.getField("msg").getBytes("ISO8859-1"), "UTF-8"));
- Dispatcher.getInstance().unicast(event, aCommand.reqEvent.getField("clientid"));// 指定的clientid
- // 回传给自己
- event = Event.createDataEvent("/conversation"); // 监听的事件
- event.setField("cmd", "answerResult");
- event.setField("code", 100);
- Dispatcher.getInstance().unicast(event, session.getId());// 当前sessionid即为clientid
- } else if (eventType.equals(Protocol.E_LISTEN)) {
- // Listen to pushed events
- doListen(aCommand);
- }
- ......
- } catch (Throwable t) {
- warn("Exception in doCommand(): " + t);
- t.printStackTrace();
- }
- }
上面代码就实现了将消息发给指定客户端,以及回传消息给自己。客户端要如何接收服务端传过来的消息,见如下代码:
- function onData(event) {
- alert(event.get("cmd"));
- alert(event.get("code"));
- alert(event.get("msg"));
- }
页面上写上此js就可以接收到服务器传过来的内容,内容全都包含在event当中了。
总结:到此为止我们对Pushlet中的定点推送消息和与浏览器参数交互有了比较深入的学习,大家可以按照这个方案开发自己想要的东西了。
另:还有我想说的就是,Pushlet这个框架是基于Servlet来做的,Servlet是需要在Tomcat这样的容器中运行的,这样一来它的客户端连接数必然受到限制。还有由于Pushlet的机制使得它并不是那么的实时。接下来我想说的是通过http长连接的方式来做。
相关推荐
【开源框架Pushlet入门(转)】 Pushlet是一款开源的实时数据推送框架,它允许服务器端主动将数据推送到客户端,而无需客户端不断轮询请求。这种技术在现代Web应用中非常常见,如实时聊天、股票报价、在线游戏等...
Pushlet 是一个开源的 Comet 框架,Pushlet 使用了观察者模型:客户端发送请求,订阅感兴趣的事件;服务器端为每个客户端分配一个会话 ID 作为标记,事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。 ...
Pushlet框架,又称为Java Pushlet,是一种基于Java的实时推送技术框架,由Marc Fleury创建并开源。Pushlet的核心概念是实现服务器向客户端的主动推送数据,而不是传统的HTTP请求-响应模式,即客户端通过轮询方式获取...
开发者可以通过阅读源码了解其工作原理,参考示例快速入门,通过配置文件定制Pushlet Server的行为。 总的来说,Comet框架的Pushlet实现是一种高效的服务器推送技术,它通过持久化连接解决了传统Web应用实时性不强...
这个名为"pushlet-record.txt"的文件可能包含了Pushlet框架的使用记录、日志信息或者是一些示例代码。分析这个文件可以帮助你更好地理解和使用Pushlet框架,例如,你可以找到服务器如何处理推送事件,客户端如何建立...
Pushlet 是一个开源的、基于Java的实时信息发布系统,它采用推送技术(Push Technology)实现服务器向客户端实时发送数据,而无需客户端频繁发起请求。这种技术在实时性要求高的场景,如股票交易、在线聊天、实时...
示例工程则提供了一个快速入门的起点,通过实际运行和调试,开发者可以快速掌握Pushlet的使用方法。 总的来说,Pushlet框架是实现Web应用中服务器主动推送消息的一个强大工具,尤其适用于需要实时交互的场景。通过...
服务器推 pushlet 服务器推 pushlet 服务器推 pushlet 服务器推 pushlet
Pushlet的核心组件是Pushlet Server和Pushlet Client。Pushlet Server作为服务端,接收并处理客户端的连接,当有新的数据可用时,会主动将数据推送到已经建立连接的客户端。Pushlet Client则是在用户端运行的程序,...
《Pushlet 2.0.4:JAVA开源框架与J2ME、JAVA WEB技术解析》 Pushlet 2.0.4是一款基于JAVA的开源框架,专为实现推送技术(Push Technology)而设计,适用于J2ME和JAVA WEB环境。在当前互联网应用中,实时数据传输的...
pushlet例子,Pushlet 是一个开源的 Comet 框架,Pushlet 使用了观察者模式:客户端发送请求,订阅感兴趣的事件;服务器端为每个客户端分配一个会话 ID 作为标记,事件源会把新产生的事件以多播的方式发送到订阅者的...
Pushlet是一种基于Java的实时数据推送技术,由荷兰JustObjects公司开发。Pushlet库的核心功能是实现实时的服务器向客户端推送数据,而无需客户端频繁发起请求,这大大提高了网络应用的效率和用户体验。以下是对...
Pushlet框架主要包括两个核心组件:Pushlet Server和Pushlet Client。Pushlet Server运行在服务器端,接收并处理客户端的连接请求,同时负责将消息推送到已连接的客户端。Pushlet Client则运行在用户的浏览器或应用...
Pushlet是基于Java的开源项目,它利用了HTTP的长连接特性,实现了服务器主动向客户端推送数据的功能,避免了传统HTTP请求-响应模型中的频繁轮询,提高了效率和用户体验。 在描述中提到的“模拟用户聊天功能”,...
3. **库文件**:jar包,包含了PushLet框架和其他依赖的第三方库,比如可能包含Jetty(一个轻量级的HTTP服务器和Servlet容器)或其他网络通信库。 4. **运行脚本**:可能包含启动和停止PushLet服务的脚本,通常用于...
Pushlet是一种基于Java的开源实现,它支持现有的Web服务器。Pushlet的核心思想是通过持久化的HTTP连接来实现实时通信。在客户端,Pushlet通常使用IFrame和JavaScript来创建一个持久的连接,使得服务器能够向浏览器...
Pushlet是一种基于Java的实时数据推送技术,它允许服务器向客户端主动推送数据,而无需客户端持续不断地轮询请求。在Web应用中,Pushlet能够显著提高用户体验,因为它减少了延迟并优化了服务器资源的使用。本示例...
Pushlet是一种基于Java的推送技术框架,用于实现实时数据从服务器向客户端的推送。Pushlet项目是由Peter Mularien开发的,它提供了一个简单、轻量级的解决方案,允许服务器端主动向浏览器或其他客户端应用程序发送...
Pushlet 是一个开源的 Comet 框架,Pushlet 使用了观察者模式:客户端发送请求,订阅感兴趣的事件;服务器端为每个客户端分配一个会话 ID 作为标记,事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。 ...
Pushlet是一种基于Java的实时通信框架,主要用于实现服务器向客户端推送数据,也就是所谓的“服务器推”技术。在传统的HTTP协议中,客户端需要不断发起请求来获取服务器的数据,而Pushlet则打破了这种模式,允许...