dwr comet实现推送,在win7 ie11打开网页慢版本以下很慢是为什么

DWR2.x的推技术也叫DWR Reverse Ajax(逆向Ajax)主要是在BS架构中,从服务器端向多个浏览器主动推数据的一种技术。&在DWR所开的线程中使用Reverse Ajax时,通过WebContextFactory.get()获取WebContext对象,进而获取脚本Session。&在DWR之外使用Reverse Ajax时,就要用到ServerContext,在Spring环境中要得到ServerContext,就需要用到Spring的ServletContextAware接口。&一、Reverse Ajax的实现有3种方式:&&&&&& DWR的逆向Ajax主要包括两种模式:主动模式和被动模式。其中主动模式包括polling和comet两种,被动模式只有piggyback这一种。&&&&& 1、piggyback方式&&&&&&&&&&& 这是默认的方式。&&&&&&&&&&& 如果后台有什么内容需要推送到前台,是要等到那个页面进行下一次ajax请求的时候,将需要推送的内容附加在该次请求之后,传回到页面。&&&&&&&&&&& 只有等到下次请求页面主动发起了,中间的变化内容才传递回页面。&&&&&& 2、comet方式&&&&&&&&&&& 当服务端建立和浏览器的连接,将页面内容发送到浏览器之后,对应的连接并不关闭,只是暂时挂起。如果后面有什么新的内容需要推送到客户端的时候直接通过前面挂起的连接再次传送数据。&&&&&&&&&&& 服务器所能提供的连接数目是一定的,在大量的挂起的连接没有关闭的情况下,可能造成新的连接请求不能接入,从而影响到服务质量。&&&&&& 3、polling方式&&&&&&&&&&& 由浏览器定时向服务端发送ajax请求,询问后台是否有什么内容需要推送,有的话就会由服务端返回推送内容。这种方式和我们直接在页面通过定时器发送ajax请求,然后查询后台是否有变化内容的实现是类似的。只不过用了dwr之后这部分工作由框架帮我们完成了。&二、使用DWR的推技术的步骤&&&&& 1、在web.xml文件中增加以下配置信息&Xml代码&&&servlet&&&&&& &servlet-name&dwr-invoker&/servlet-name&&&&&& &servlet-class&uk.ltd.getahead.dwr.DWRServlet&/servlet-class&&&&&& &init-param&&&&&&&&&& &param-name&debug&/param-name&&&&&&&&&& &param-value&true&/param-value&&&&&& &/init-param&&&&&&&&&&&&& &!-- DWR默认采用piggyback方式 --&&&&&&&&&&&&& &!-- 使用polling和comet的方式 --&&&&&& &init-param&&&&&&&&&& &param-name&pollAndCometEnabled&/param-name&&&&&&&&&& &param-value&true&/param-value&&&&&& &/init-param&&&&&&&&&&&&& &!-- comet方式 --&&&&&& &!--&&&&&&& &init-param&&&&&&&&&& &param-name&activeReverseAjaxEnabled&/param-name&&&&&&&&&& &param-value&true&/param-value&&&&&& &/init-param&&&&&&& --&&&&&&&&&&&&&& &!-- polling方式:在comet方式的基础之上,再配置以下参数 --&&&&&& &!--&&&&&&& &init-param&&&&&&&&&& &param-name&org.directwebremoting.extend.ServerLoadMonitor&/param-name&&&&&&&&&& &param-value&org.directwebremoting.impl.PollingServerLoadMonitor&/param-value&&&&&& &/init-param&&&&&&& --&&&&&&&&&&&&&&& &!-- 毫秒数。页面默认的请求间隔时间是5秒 --&&&&&& &!--&&&&&&& &init-param&&&&&&&&&& &param-name&disconnectedTime&/param-name&&&&&&&&&& &param-value&60000&/param-value&&&&&&&& &/init-param&&&&&&& --&&&&&&&&&&&&&& &load-on-startup&1&/load-on-startup&&&&&&&&&&&/servlet&&&&&&servlet-mapping&&&&&& &servlet-name&dwr-invoker&/servlet-name&&&&&& &url-pattern&/dwr/*&/url-pattern&&&&/servlet-mapping&&&&servlet&&&servlet-name&dwr-invoker&/servlet-name&&&servlet-class&uk.ltd.getahead.dwr.DWRServlet&/servlet-class&&&init-param&&&param-name&debug&/param-name&&&param-value&true&/param-value&&&/init-param&&&!-- DWR默认采用piggyback方式 --&&&!-- 使用polling和comet的方式 --&&&init-param&&&param-name&pollAndCometEnabled&/param-name&&&param-value&true&/param-value&&&/init-param&&&!-- comet方式 --&&&!--&&init-param&&&param-name&activeReverseAjaxEnabled&/param-name&&&param-value&true&/param-value&&&/init-param&&--&&&!-- polling方式:在comet方式的基础之上,再配置以下参数 --&&&!--&&init-param&&&param-name&org.directwebremoting.extend.ServerLoadMonitor&/param-name&&&param-value&org.directwebremoting.impl.PollingServerLoadMonitor&/param-value&&&/init-param&&--&&&&&!-- 毫秒数。页面默认的请求间隔时间是5秒 --&&&!--&&init-param&&&param-name&disconnectedTime&/param-name&&&param-value&60000&/param-value&&&/init-param&&--&&&load-on-startup&1&/load-on-startup&&&&&&&&/servlet&&&servlet-mapping&&&servlet-name&dwr-invoker&/servlet-name&&&url-pattern&/dwr/*&/url-pattern&&&/servlet-mapping&Xml代码&&&listener&&&&&&&&&& &listener-class&org.directwebremoting.servlet.EfficientShutdownServletContextAttributeListener&/listener-class&&&&/listener&&&&listener&&&&&&&&& &listener-class&org.directwebremoting.servlet.EfficientShutdownServletContextAttributeListener&/listener-class&&&/listener&Xml代码&&&listener&&&&&&&&&& &listener-class&org.directwebremoting.servlet.EfficientShutdownServletContextListener&/listener-class&&&&/listener&&&&listener&&&&&&&&& &listener-class&org.directwebremoting.servlet.EfficientShutdownServletContextListener&/listener-class&&&/listener&&&&& 2、在dwr.xml中增加以下配置信息&Xml代码&&&create creator="new" javascript="DWRHelper"&&&&&& &param name="class" value="com.cjm.web.dwr.DWRHelper"/&&&&&& &include method="addMessage"/&&&&&& &include method="test"/&&&&/create&&&&&&convert converter="bean" match="com.cjm.web.dwr.Message"&&&&&& &param name="include" value="id,text"/&&&&/convert&&&&create creator="new" javascript="DWRHelper"&&&param name="class" value="com.cjm.web.dwr.DWRHelper"/&&&include method="addMessage"/&&&include method="test"/&&&/create&&&convert converter="bean" match="com.cjm.web.dwr.Message"&&&param name="include" value="id,text"/&&&/convert&&&&& 3、pojo类Message的源码&Java代码&&public class Message {&&&&&& private long id = System.currentTimeMillis();&&&&&& private S&&&&&&&&&&&&& public Message(){&&&&&&&&&&&&&&&&& }&&&&&&&&&&&&& public Message(String newText){&&&&&&&&&& text = newT&&&&&& }&&&&&&&&&&&&& public long getId() {&&&&&&&&&&&&&&&& }&&&&&& public void setId(long id) {&&&&&&&&&& this.id =&&&&&& }&&&&&& public String getText() {&&&&&&&&&&&&&&&& }&&&&&& public void setText(String text) {&&&&&&&&&& this.text =&&&&&& }&&&}&&public class Message {&private long id = System.currentTimeMillis();&private S&public Message(){&}&public Message(String newText){&text = newT&}&public long getId() {&&}&public void setId(long id) {&this.id =&}&public String getText() {&&}&public void setText(String text) {&this.text =&}&}&&&&& 4、DWRHelper类源码&Java代码&&public class DWRHelper {&&&&&& private static LinkedList&Message& messages = new LinkedList&Message&();&&&&&& private static ReentrantLock lock = new ReentrantLock(); //JDK5锁&&&&&&&&&&&&& public void addMessage(String text){&&&&&&&&&& try{&&&&&&&&&&&&&& lock.lock();&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if(text!=null && text.trim().length()&0){&&&&&&&&&&&&&&&&&& messages.addFirst(new Message(text));&&&&&&&&&&&&&&&&&& if(messages.size()&10){&&&&&&&&&&&&&&&&&&&&&& messages.removeLast();&&&&&&&&&&&&&&&&&& }&&&&&&&&&&&&&& }&&&&&&&&&& }catch(Exception ex){&&&&&&&&&&&&&& ex.printStackTrace();&&&&&&&&&& }finally{&&&&&&&&&&&&&& lock.unlock();&&&&&&&&&& }&&&&&&&&&&&&&&&&&&&&& //获得DWR上下文&&&&&&&&&& WebContext webContext = WebContextFactory.get();&&&&&&&&&&&&&&&&&&&&& //获取当前页面URL,比如/ext3/test_tag.jsp&&&&&&&&&& String currentPage = webContext.getCurrentPage();&&&&&&&&&&&&&&&&&&&&& //当前脚本sessin&&&&&&&&&& ScriptSession scriptSession = webContext.getScriptSession();&&&&&&&&&&&&&&&&&&&&& //设置页面控件的值&&&&&&&&&& Util util = new Util(scriptSession);&&&&&&&&&& util.setValue("text", ""); //这里是清空页面输入框的值&&&&&&&&&&&&&&&&&&&&& //设置脚本sessin的属性值&&&&&&&&&& scriptSession.setAttribute("uid", "cjm");&&&&&&&&&&&&&&&&&&&&& //获取脚本session的属性值&&&&&&&&&& for(Iterator it=scriptSession.getAttributeNames();it.hasNext();){&&&&&&&&&&&&&& String attrName = (String)it.next();&&&&&&&&&&&&&& System.out.println(attrName + "=" + scriptSession.getAttribute(attrName));&&&&&&&&&& }&&&&&&&&&&&&&&&&&&&&& //获取所有浏览当前页面的脚本session&&&&&&&&&& Collection&ScriptSession& sessions = webContext.getScriptSessionsByPage(currentPage);&&&&&&&&&&&&&&&&&&&&& Util utilAll = new Util(sessions);&&&&&&&&&&&&&&&&&&&&& //执行客户端脚本&&&&&&&&&& ScriptBuffer script = new ScriptBuffer();&&&&&&&&&& script.appendScript("clientFunction(")&&&&&&&&&&&& .appendData(scriptSession.getAttribute("uid"))&&&&&&&&&&&& .appendScript(");");&&&&&&&&&&&&&&&&&&&&& for(ScriptSession session: sessions){&&&&&&&&&&&&&& session.addScript(script);&&&&&&&&&& }&&&&&&&&&&&&&&&&&&&&& //更新这些脚本session的一些元素&&&&&&&&&& utilAll.removeAllOptions("messages");&&&&&&&&&& utilAll.addOptions("messages", messages, "id", "text");&&&&&& }&&&}&&public class DWRHelper {&private static LinkedList&Message& messages = new LinkedList&Message&();&private static ReentrantLock lock = new ReentrantLock(); //JDK5锁&public void addMessage(String text){&try{&lock.lock();&if(text!=null && text.trim().length()&0){&messages.addFirst(new Message(text));&if(messages.size()&10){&messages.removeLast();&}&}&}catch(Exception ex){&ex.printStackTrace();&}finally{&lock.unlock();&}&//获得DWR上下文&WebContext webContext = WebContextFactory.get();&//获取当前页面URL,比如/ext3/test_tag.jsp&String currentPage = webContext.getCurrentPage();&//当前脚本sessin&ScriptSession scriptSession = webContext.getScriptSession();&//设置页面控件的值&Util util = new Util(scriptSession);&util.setValue("text", ""); //这里是清空页面输入框的值&//设置脚本sessin的属性值&scriptSession.setAttribute("uid", "cjm");&//获取脚本session的属性值&for(Iterator it=scriptSession.getAttributeNames();it.hasNext();){&String attrName = (String)it.next();&System.out.println(attrName + "=" + scriptSession.getAttribute(attrName));&}&//获取所有浏览当前页面的脚本session&Collection&ScriptSession& sessions = webContext.getScriptSessionsByPage(currentPage);&Util utilAll = new Util(sessions);&//执行客户端脚本&ScriptBuffer script = new ScriptBuffer();&script.appendScript("clientFunction(")&& .appendData(scriptSession.getAttribute("uid"))&& .appendScript(");");&for(ScriptSession session: sessions){&session.addScript(script);&}&//更新这些脚本session的一些元素&utilAll.removeAllOptions("messages");&utilAll.addOptions("messages", messages, "id", "text");&}&}&&&& 5、JSP页面源码&Html代码&&&%@ page language="java" pageEncoding="UTF-8"%&&&&!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&&&&html&&&& &head&&&&&& &script type='text/javascript' src='/ext3/dwr/engine.js'&&/script&&&&&& &script type='text/javascript' src='/ext3/dwr/util.js'&&/script&&&&&& &script type='text/javascript' src='/ext3/dwr/interface/DWRHelper.js'&&/script&&&& &/head&&&&&&&&& &!-- 通过 dwr.engine.setActiveReverseAjax(true); 启动该页面的Reverse Ajax功能& --&&&& &body onload="dwr.engine.setActiveReverseAjax(true);sendMessage();"&&&&&& &p&输入信息: &input id="text" onkeypress="dwr.util.onReturn(event, sendMessage)" /&&&&&&&& &input type="button" value="Send" onclick="sendMessage()" /&&/p&&&&&&&& &script type="text/javascript"&&&&&&&&&& function sendMessage() {&&&&&&&&&&&&&& DWRHelper.addMessage(dwr.util.getValue("text"));&&&&&&&&&& }&&&&&& &/script&&&&&&&&&&&&& &hr/&&&&&& &select id="messages"&&/select&&&&&&&&&&& &/body&&&&/html&&&
以上文章从别的地方直接复制过来的,楼主懒得详细描述。。后面附实例下载地址,里面有详细的注释说明,主要实现DWR推送、线程监听、事件监听、主动推送。。写得不好,请见谅。。然后有个特别需要注意的,部署好项目以后,访问的方式是:,特别注意indexTo,因为是Spring MVC转发请求。。测试的时候,打开两个页面,分别是生产数据页面还有查看数据页面,当点击生产数据页面后,查看数据页面就会收到从后台推送过来的数据。。
阅读(...) 评论()dwr做comet的完整实现_软件学园_科技时代_新浪网
dwr做comet的完整实现
来源:http://www.blogjava.net/harvey4tian/archive//212542.html  场景:页面comet.jsp接受服务器推送的信息并显示,页面action.jsp执行一个动作,调用DwrServer.perform方法,perform方法做某些事,并发送事件信息PerformInfo。NotifyClient监听事件,当接收到PerformInfo后,把PerformInfo的信息发送到comet.jsp页面。这个场景模拟了页面1执行了一个时间比较长或复杂的任务,任务执行情况可以反馈到页面2(比如模式窗口)。  信息载体PerformInfo.java import java.util.D public class PerformInfo {
* @return the id
public int getId() {
* @param id the id to set
public void setId(int id) {
* @return the msg
public String getMsg() {
* @param msg the msg to set
public void setMsg(String msg) {
this.msg =
* @return the time
public Date getTime() {
* @param time the time to set
public void setTime(Date time) {
this.time =
}} import java.util.D public class PerformInfo {
* @return the id
public int getId() {
* @param id the id to set
public void setId(int id) {
* @return the msg
public String getMsg() {
* @param msg the msg to set
public void setMsg(String msg) {
this.msg =
* @return the time
public Date getTime() {
* @param time the time to set
public void setTime(Date time) {
this.time =
Spring的事件InfoEvent.java import org.springframework.context.ApplicationE public class InfoEvent extends ApplicationEvent {
public InfoEvent(Object source){
super(source);
DwrService.java 执行任务,就是写了100遍PerformInfo,需要实现ApplicationContextAware接口 import java.util.D import org.springframework.context.ApplicationC import org.springframework.context.ApplicationContextA import org.springframework.context.ApplicationE public class DwrService implements ApplicationContextAware{
private ApplicationC
public void setApplicationContext(ApplicationContext ctx) {
this.ctx =
public void perform(){
for (int i=0; i<100; i++){
PerformInfo info = new PerformInfo();
info.setId(i);
info.setMsg("发送"+i+"信息");
info.setTime(new Date());
InfoEvent evt = new InfoEvent(info);
ctx.publishEvent(evt);
}}NotifyClient.java监听事件,发送信息到页面。实现ApplicationListener,ServletContextAware接口,对中文需要编码 import java.io.UnsupportedEncodingE import java.util.C import javax.servlet.ServletC import javax.servlet.http.HttpS import javax.servlet.http.HttpSessionBindingE import org.springframework.web.context.ServletContextA import org.directwebremoting.ScriptB import org.directwebremoting.ScriptS import org.directwebremoting.ServerC import org.directwebremoting.ServerContextF import org.springframework.context.ApplicationC import org.springframework.context.ApplicationContextA import org.springframework.context.ApplicationE import org.springframework.context.ApplicationL public class NotifyClient implements ApplicationListener,ServletContextAware{
private ServletContext servletContext =
public void setServletContext( ServletContext servletContext )
this.servletContext = servletC
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof InfoEvent) {
PerformInfo info = (PerformInfo)event.getSource();
System.out.println(info.getMsg());
//Collection<ScriptSession> sessions=ctx.getAllScriptSessions();
ServerContext ctx = ServerContextFactory.get(servletContext );
Collection<ScriptSession> sessions =
ctx.getScriptSessionsByPage("/dwrcomet/comet.jsp");
for (ScriptSession session : sessions) {
ScriptBuffer script = new ScriptBuffer();
String s2 =
s = java.net.URLEncoder.encode(info.getMsg(),"UTF-8");
s2 = java.net.URLEncoder.encode("通知结束","UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
if (info.getId()<99){
script.appendScript("putInfo('")
.appendScript(info.getId()+":"+s)
.appendScript("'); ");
script.appendScript("alert(decodeURI('").
appendScript(s2).appendScript("')); ");
System.out.println(script.toString());
session.addScript(script);
}}action.jsp执行任务<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String root = request.getContextPath(); %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>
<title>doing</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<script type='text/javascript' src='<%=root%>/dwr/engine.js'></script><script type='text/javascript' src='<%=root%>/dwr/util.js'></script><script type='text/javascript' src='<%=root%>/dwr/interface/DwrService.js'></script>
<input name='action' onclick='DwrService.perform(); ' type="button" value="行动"/>
</body></html>comet.jsp接受信息。关键是增加onload="dwr.engine.setActiveReverseAjax(true); ",还可以根据user或session id判断是否是自己的信息.<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String root = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+root+"/"; %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>
<base href="<%=basePath%>">
<title>Comet with DWR</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<body onload="dwr.engine.setActiveReverseAjax(true); "><script type='text/javascript' src='<%=root%>/dwr/engine.js'></script><script type='text/javascript' src='<%=root%>/dwr/util.js'></script><script type="text/javascript">
var user = '<%=request.getParameter("user")%>';
function putInfo(data) {
var d = decodeURI(data);
var text = dwr.util.getValue('info');
dwr.util.setValue('info',text+'\n'+d);
}</script><br/><textarea rows="20" cols="100" id='info'></textarea></body></html>applicationContext.xml配置了NotifyClient和DwrService,这两个bean实现了ApplicationContextAware<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans>
<bean id="notifyClient" class="et.NotifyClient">
<bean id="dwrService" class="et.DwrService"></bean></beans>dwr.xml<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE dwr PUBLIC
"-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
"http://www.getahead.ltd.uk/dwr/dwr10.dtd"><dwr>
<create creator="spring" javascript="DwrService">
<param name="beanName" value="dwrService" />
</create>
</allow></dwr>web.xml定义了dwr的comet控制,关键是pollAndCometEnabled=true<?xml version="1.0" encoding="UTF-8"?><web-app version="2.4"
xmlns="/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="/xml/ns/j2ee
/xml/ns/j2ee/web-app_2_4.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app*.xml</param-value>
</context-param>
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>
org.springframework.web.context.ContextLoaderServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet> <!--dwr servlet-->
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>pollAndCometEnabled</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping></web-app>运行时要先打开comet.jsp,然后执行action.jsp
【】【】【
】【打印】【】
不支持Flash
《程序员》的其他文章
不支持Flash您现在正在浏览:
Web端服务器推送技术原理分析及dwr框架简单的使用
发布时间:
17:33:50 &
浏览次数:
摘要: 采用了Comet技术的服务器在客户机做出一个请求后,和客户机建立一个永久的连接,然后服务器会根据客户机...
Web端服务器推送技术原理分析及dwr框架简单的使用
1 背景
“服务器推送技术”(ServerPushing)是最近Web技术中最热门的一个流行术语。它是继“Ajax”之后又一个倍受追捧的Web技术。“服务器推送技术”最近的流行跟“Ajax ”有着密切的关系。
随着 Ajax技术的兴起,让广大开发人员又一次看到了使用浏览器来替代桌面应用的机会,并且这次机会非常大。Ajax将整个页面的刷新变成页面局部的刷新,并且数据的传送是以异步方式进行,这使得网络延迟带来的视觉差异将会消失。
但是,在浏览器中的 Ajax应用中存在一个致命的缺陷无法满足传统桌面系统的需求。那就是“服务器发起的消息传递”(Server-Initiated Message Delivery)。在很多的应用当中,服务器软件需要向客户端主动发送消息或信息。因为服务器掌握着系统的主要资源,能够最先获得系统的状态变化和事件的发生。当这些变化发生的时候,服务器需要主动的向客户端实时的发送消息。例如股票的变化。在传统的桌面系统这种需求没有任何问题,因为客户端和服务器之间通常存在着持久的连接,这个连接可以双向传递各种数据。而基于HTTP协议的 Web应用却不行。
2 客户端得到通知的方式
图1 传统web 访问机制
我们知道, Web的访问机制天生是设计用来 pull数据的,如图 1,也就是只允许 Browser端主动发起请求,server是被动的响应,不允许Server向 Browser发出一个 connection请求,也就是说没有为server向 Browser
push数据提供设计实现.虽然没有直接的实现方法,却可以使用一些变通的方式完成类似的功能。
2.1 传统轮询
在 Web早期,这一点常使用meta刷新实现。这将自动指示浏览器在指定秒数之后重新装载页面,从而支持简陋的轮询(polling)。例如在HTML文件中加入
,实际上就是 HTTP 头标告知浏览器每 12 秒更新一次文档。
优点 :不需要服务器端的配置。
缺点 :
a) 糟糕的用户体验
b) 对服务器的压力很大,并且造成带宽的极大浪费。
2.2 Ajax 轮询
Ajax隔一段时间(通常使用JavaScript的setTimeout函数)就去服务器查询是否有改变,从而进行增量式的更新。但是间隔多长时间去查询成了问题,因为性能和即时性造成了严重的反比关系。间隔太短,连续不断的请求会冲垮服务器,间隔太长,务器上的新数据就需要越多的时间才能到达客户机。
优点:
a) 不需要太多服务器端的配置。
b) 降低带宽的负荷(因为服务器返回的不是完整页面)。
缺点:
a) 对服务器的压力并不会有明显的减少。
b) 实时性差,有一定的延迟。
应用: 这是一项非常常见的技术,例如,大多数 webmail应用程序就是通过这种技术在电子邮件到达时显示电子邮件的。
2.3 Comet
Comet方式通俗的说就是一种长连接机制(long lived http)。同样是由Browser端主动发起请求,但是Server端以一种似乎非常慢的响应方式给出回答。这样在这个期间内,服务器端可以使用同一个connection把要更新的数据主动发送给Browser。因此请求可能等待较长的时间,期间没有任何数据返回,但是一旦有了新的数据,它将立即被发送到客户机。Comet又有很多种实现方式,但是总的来说对Server端的负载都会有增加.虽然对于单位操作来说,每次只需要建议一次connection,但是由于connection是保持较长时间的,对于 server端的资源的占用要有所增加。
优点: 实时性好(消息延时小);性能好(能支持大量用户)
缺点: 长期占用连接,丧失了无状态高并发的特点。
应用: 股票系统、实时通讯。
2.4 Flash XML Socket
这种方案实现的基础是:一、Flash提供了 XMLSocket类。二、 JavaScript 和 Flash的紧密结合:在 JavaScript可以直接调用 Flash程序提供的接口。
缺点:
a) 因为XMLSocket没有HTTP隧道功能,XMLSocket类不能自动穿过防火墙;
b) 因为是使用套接口,需要设置一个通信端口,防火墙、代理服务器也可能对非HTTP通道端口进行限制;
应用: 网络聊天室,网络互动游戏。
2.5 Java Applet 套接口
在客户端使用 Java Applet,通过 java.net.Socket或java.net.DatagramSocket或java.net.MulticastSocket 建立与服务器端的套接口连接,从而实现“服务器推送 ”。
缺点: 需要客户端安装 JAVA虚拟机。
3 Comet 介绍
Comet 有时也称反向 Ajax或服务器端推技术(server-side push)。其思想很简单:将数据直接从服务器推到浏览器,而不必等到浏览器请求数据。听起来简单,但是如果熟悉Web 应用程序,尤其是HTTP协议,那么您就会知道,这绝不简单。实现Comet风格的 Web应用程序,同时保证在浏览器和服务器上的可伸缩性,这只是在最近几年才成为可能。目前一些主流网站都有类似的原理,例如:webQQ、开心网、校内等等,它们中消息动态都是采用类似的技术,只是具体实现方式不一样。
COMET的精髓就在于用服务器与javascript来维持浏览器的长连接,同时完成服务器端事件的浏览器端响应。这样的事件广播机制是跨网络的,同时也是实时的。
采用了 Comet技术的服务器在客户机做出一个请求后,和客户机建立一个永久的连接,然后服务器会根据客户机的请求不断把数据包推向客户,这个推的过程是不间断的。由服务器推向客户机的数据在客户机的浏览器上会不断产生新的内容,而且不会产生Client
pull那样的HTML文档头,从而大大减少了延迟的时间,向(服务器响应--客户机请求)同步迈进了一步。
服务器推送通常效率要比客户端拖曳效率高,因为它不必为后续数据建立新的连接。由于始终保持连接,即使没有数据传输时也是这样,因此服务器必须愿意分配这些TCP/IP端口,对于TCP/IP端口数有限的服务器这将是一个严重的问题。
客户端拖曳效率低,因为这必须每次为传送数据建立新的连接。但是它不必始终保持连接。在实际情况中,建立HTTP连接通常需要花费相当多的时间,多达一秒甚至更多。因此从性能上考虑,服务器推送对于最终用户更有吸引力,特别是对于需要经常更新信息的情况下。
服务器推送相对客户端拖曳的另一点优势是,服务器推送相对比较容易控制。例如,服务器每一次推送时都保持一个连接,但它又随时可以关闭其中的任何连接,而不需要在服务器上设置特殊的算法。而客户端拖曳在同样的情况下要麻烦许多,它每次要与服务器建立连接,服务器为了处理将客户端拖曳请求与特定的最终用户匹配等情况,需要使用相当麻烦的算法。
如上所述,在服务器推送中,多个响应中连接始终保持,使服务器可在任何时间发送更多的数据。一个明显的好处是服务器完全能够控制更新数据的时间和频率。另外,这种方法效率高,因为始终保持连接。缺点是保持连接状态会浪费服务器端的资源。服务器推送还比较容易中断。
4 Comet 实现(Java语言)
4.1 死循环法
最简单的自然是死循环法,如果使用观察者模式则可以进一步提高性能。
但是这种做法的缺点在于客户端请求了这个 servlet后, web 服务器会开启一个线程执行 servlet 的代码,而 servlet 由迟迟不肯结束,造成该线程也无法被释放。于是乎,一个客户端一个线程,当客户端数量增加时,服务器依然会承受很大的负担。
4.2 改写web服务器
目前的趋势是从 web 服务器内部入手,用 nio ( JDK 1.4 提出的 java.nio 包)改写 request/response 的实现,再利用线程池增强服务器的资源利用率,从而解决这个问题,目前支持这一非 J2EE 官方技术的服务器有 Glassfish 和 Jetty 。
JDK 1.4 版本 ( 包括之后的版本 ) 最显著的新特性就是增加了 NIO(New IO) ,能够以非阻塞的方式处理网络的请求,这就使得在 Java 中只需要少量的线程就能处理大量的并发请求了。
Jetty 6设计来处理大量并发连接,它使用Java语言的不堵塞 I/O(java.nio)库并且使用优化的输出缓冲架构。Jetty也有一个处理长连接的杀手锏:一个称为 Continuations的特性。
Grizzly 作为 GlassFish 中非常重要的一个项目,就是用 NIO 的技术来实现应用服务器中的高性能纯 Java 的 HTTP 引擎。 Grizzly 还是一个独立于 GlassFish 的框架结构,可以单独用来扩展和构建自己的服务器软件。
特点: 使用 NIO 不是一件简单的技术,它的一些特点使得编程的模型比原来阻塞的方式更为复杂。
4.3 使用框架
基于 Java 的成熟的服务器推送框架有 DWR 。
DWR是一个开放源码的使用Apache许可协议的解决方案,它包含服务器端Java库、一个 DWR
servlet以及 JavaScript库。虽然 DWR不是 Java平台上唯一可用的Ajax-RPC 工具包,但是它是最成熟的,而且提供了许多有用的功能。从最简单的角度来说,DWR是一个引擎,可以把服务器端Java对象的方法公开给JavaScript 代码。使用DWR 可以有效地从应用程序代码中把Ajax的全部请求 -响应循环消除掉。这意味着客户端代码再也不需要直接处理XMLHttpRequest对象或者服务器的响应。不再需要编写对象的序列化代码或者使用第三方工具才能把对象变成XML。甚至不再需要编写servlet代码把 Ajax请求调整成对 Java域对象的调用。
DWR 从 2.0开始增加了 push 功能 , 也就是在异步传输的情况下可以从 Web-Server 端发送数据到 Browser
一个简单的dwr推送程序
第一步 将dwr相关的jar包导入到工程
第二步 配置web.xml文件
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="/xml/ns/javaee
/xml/ns/javaee/web-app_2_5.xsd">
dwr-invoker
org.directwebremoting.servlet.DwrServlet
activeReverseAjaxEnabled
true
maxWaitAfterWrite
-1
dwr-invoker
/dwr/*
第三步编写com.im.service.SendPushService类
public class SendPushService {
//发送消息
public void send(String msg) {
System.out.println("==========调用了send方法==========");
ScriptBuffer scriptBuffer = new ScriptBuffer(); //构造js脚本
WebContext webContext=WebContextFactory.get();
ScriptSession myScSession = webContext.getScriptSession();
scriptBuffer.appendScript("dwrtest(");
scriptBuffer.appendData(msg);
scriptBuffer.appendScript(")");
Util util = new Util(myScSession);
util.addScript(scriptBuffer); //向客户端推送消息
}
}
第四步 在dwr.xml文件定义向外暴露的接口
第五步: 编写jsp文件.
本周热门资讯排行}

我要回帖

更多关于 dwr comet 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信