首先,通过tomcat的comet来实现服务器推的技术要在tomcat的Server.xml文件中修改一下设置:
改为:
其次,服务器端使用实现了org.apache.catalina.comet.CometProcessor接口的HTTPservlet来处理,在其中实现这个接口的event方法,要加入tomcat的catalina.jar这个包(有可能待版本号),简单处理如下:
这只是最基础的实现,如果要处理复杂一些的情况就多实现一些。服务器端实现关键点比较单一,就是使用PrintWriter pw = response.getWriter();往浏览器端写入东西,写入的东西是字符串文本还是脚本就看具体情况了。
一、我们通过XMLHttpRequest来实现
在browser端会这么写:
然而,这代码只能在Firefox下能正常工作,因为request.readyState == 3时读取返回的数据在其他浏览器中没有被支持(IE也不例外),会报错,并且目前在用户群体中使用Firefox的比例非常小,IE还是主流的。所以这种方式局限明显。
二、Iframe极简单的实现
浏览器端:
服务器端:
就是往iframe里写一段javascript脚本。但是这种情况,Firefox和IE的标签会一直转圈(进度条一直没完),不美观。另外,这种情况,如果往浏览器端写入字符文本,而不是脚本,那么在Firefox下会实时更新,但是在IE下要达到一定字节才会更新,并且写入的数据一直在里面,如果需要的话就做一下过滤。
三、Iframe改进版
解决IE下和Firefox下进度条的问题,我们采取往iframe里写入脚本的方式来实现
html页面:
服务器端:
但是这样的方式,IE和Firefox正常啦,但是chrome还是转圈的,找到解决方法了再来更新,如果有大神们找到请告诉一下小弟,谢谢!
将普通情况的
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
改为:
<Connector connectionTimeout="20000" port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" redirectPort="8443"/>
其次,服务器端使用实现了org.apache.catalina.comet.CometProcessor接口的HTTPservlet来处理,在其中实现这个接口的event方法,要加入tomcat的catalina.jar这个包(有可能待版本号),简单处理如下:
public class TestComet extends HttpServlet implements CometProcessor {
private static final long serialVersionUID = 1L;
private RandomSender randomSender = null;
private final static int TIMEOUT = 60*1000;
@Override
public void event(final CometEvent event) throws IOException, ServletException {
HttpServletRequest rq = event.getHttpServletRequest();
HttpServletResponse rp = event.getHttpServletResponse();
if(event.getEventType() == CometEvent.EventType.BEGIN){
rq.setAttribute("org.apache.tomcat.comet.timeout", TIMEOUT);
randomSender = new RandomSender(rp);
Thread thread = new Thread(randomSender);
thread.start();
}else if(event.getEventType() == CometEvent.EventType.ERROR){
event.close();
}else if(event.getEventType() == CometEvent.EventType.END){
event.close();
}else if(event.getEventType() == CometEvent.EventType.READ){
throw new UnsupportedOperationException("this servlet does not accept data");
}
}
}
public class RandomSender implements Runnable {
private boolean running = true;
private ServletResponse response;
Random rand;
public RandomSender(ServletResponse rq) {
this.response =rq;
rand = new Random();
}
@Override
public void run() {
while(running){
try {
PrintWriter pw = response.getWriter();
pw.println(rand.nextInt(10));
pw.flush();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这只是最基础的实现,如果要处理复杂一些的情况就多实现一些。服务器端实现关键点比较单一,就是使用PrintWriter pw = response.getWriter();往浏览器端写入东西,写入的东西是字符串文本还是脚本就看具体情况了。
一、我们通过XMLHttpRequest来实现
在browser端会这么写:
<script type="text/javascript">
function go(){
url = "http://localhost:8080/comet/cometTest";
var request;
request = new XMLHttpRequest();
request.open("GET",url,true);
request.setRequestHeader("Content-Type","applicatin/x-javascript;");
request.onreadystatechange = function(){
if(request.readyState == 3){
if(request.status == 200){
if(request.responseText){
//这里需要注意的是:往后的每次数据都包含以前的数据,也就是说以前的数据还在request.responseText中
document.getElementById("number").innerHTML = request.responseText;
}
}
}
};
request.send(null);
}
</script>
然而,这代码只能在Firefox下能正常工作,因为request.readyState == 3时读取返回的数据在其他浏览器中没有被支持(IE也不例外),会报错,并且目前在用户群体中使用Firefox的比例非常小,IE还是主流的。所以这种方式局限明显。
二、Iframe极简单的实现
浏览器端:
<title>test comet</title>
<script type="text/javascript">
//定义一个js函数,由服务断写到iframe里的js调用,但是这时,IE标签上的圆圈一直在转
function changeNumber(num) {
document.getElementById("number").innerHTML = num;
}
</script>
</head>
<body>
<h1>test comet</h1>
<div id="number">1111</div>
<iframe id="iframe" src="cometIframeTest"></iframe>
</body>
服务器端:
PrintWriter pw = response.getWriter();
pw.println("<script>parent.changeNumber("+rand.nextInt(10)+")</script>");
pw.flush();
就是往iframe里写一段javascript脚本。但是这种情况,Firefox和IE的标签会一直转圈(进度条一直没完),不美观。另外,这种情况,如果往浏览器端写入字符文本,而不是脚本,那么在Firefox下会实时更新,但是在IE下要达到一定字节才会更新,并且写入的数据一直在里面,如果需要的话就做一下过滤。
三、Iframe改进版
解决IE下和Firefox下进度条的问题,我们采取往iframe里写入脚本的方式来实现
html页面:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>comet test</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<div id="content">show the message</div>
<script type="text/javascript">
var comet = {
connection : false,
iframediv : false,
initialize: function() {
if (navigator.appVersion.indexOf("MSIE") != -1) {
// IE
comet.connection = new ActiveXObject("htmlfile");
comet.connection.open();
comet.connection.write("<html>");
comet.connection.write("<script>document.domain = '"+document.domain+"'");
comet.connection.write("</html>");
comet.connection.close();
comet.iframediv = comet.connection.createElement("div");
comet.connection.appendChild(comet.iframediv);
comet.connection.parentWindow.comet = comet;
comet.iframediv.innerHTML = "<iframe id='comet_iframe' src='IECometServlet'></iframe>";
} else if (navigator.appVersion.indexOf("KHTML") != -1) {
// KHTML
comet.connection = document.createElement('iframe');
comet.connection.setAttribute('id','iframe');
comet.connection.setAttribute('src','IECometServlet');
with (comet.connection.style) {
position = "absolute";
left = top = "-100px";
height = width = "1px";
visibility = "hidden";
}
document.body.appendChild(comet.connection);
} else {
// For other browser (Firefox...)
comet.connection = document.createElement('iframe');
comet.connection.setAttribute('id','iframe');
with (comet.connection.style) {
left = top = "-100px";
height = width = "1px";
visibility = "hidden";
display = 'none';
}
comet.iframediv = document.createElement('iframe');
comet.iframediv.setAttribute('src', 'IECometServlet');
comet.connection.appendChild(comet.iframediv);
document.body.appendChild(comet.connection);
}
},
changeNumber: function (num) {
document.getElementById('content').innerHTML = num;
},
onUnload: function() {
if (comet.connection) {
comet.connection = false;
}
}
}
if (window.attachEvent){
window.attachEvent("onload", comet.initialize);
window.attachEvent("onunload", comet.onUnload);
}else{
window.addEventListener("load", comet.initialize, false);
window.addEventListener("unload", comet.onUnload, false);
}
</script>
</body>
</html>
服务器端:
package org.wz.comet.ie;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.comet.CometEvent;
import org.apache.catalina.comet.CometProcessor;
public class IECometServlet extends HttpServlet implements CometProcessor {
private static final long serialVersionUID = 1L;
public static ArrayList<HttpServletResponse> connections = new ArrayList<HttpServletResponse>();
public void init() throws ServletException {
}
public void destroy() {
connections.clear();
}
public void event(CometEvent event) throws IOException, ServletException {
HttpServletRequest request = event.getHttpServletRequest();
HttpServletResponse response = event.getHttpServletResponse();
if (event.getEventType() == CometEvent.EventType.BEGIN) {
event.setTimeout(Integer.MAX_VALUE);
MessageSender tp = new MessageSender(response);
Thread t = new Thread(tp);
t.start();
synchronized (connections) {
connections.add(response);
}
} else if (event.getEventType() == CometEvent.EventType.ERROR) {
synchronized (connections) {
connections.remove(response);
}
event.close();
} else if (event.getEventType() == CometEvent.EventType.END) {
synchronized (connections) {
connections.remove(response);
}
event.close();
} else if (event.getEventType() == CometEvent.EventType.READ) {
event.close();
}
}
}
package org.wz.comet.ie;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
import javax.servlet.ServletResponse;
public class MessageSender implements Runnable{
private boolean running = true;
private ServletResponse response;
public MessageSender(ServletResponse response) {
this.response = response;
}
@Override
public void run() {
while(running){
PrintWriter writer;
try {
writer = response.getWriter();
writer.println("<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">");
writer.println("<html><head>"
+ "<script type=\"text/javascript\">var comet = window.parent.comet;</script>"
+ "</head><body>");
writer.print("<script type=\"text/javascript\">");
writer.println("comet.changeNumber('"+new Random().nextInt(100)+"');");
writer.print("</script>");
writer.print("</body>");
writer.print("</html>");
writer.flush();
} catch (IOException e) {
System.err.println("IOException------------------");;
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
System.err.println("InterruptedException---------------------");
}
}
}
}
但是这样的方式,IE和Firefox正常啦,但是chrome还是转圈的,找到解决方法了再来更新,如果有大神们找到请告诉一下小弟,谢谢!
参考资料:
点击打开链接
特别感谢这位前辈的博客:点击打开链接