模拟comet的实现

本文没有使用任何comet服务器, 只是利用tomcat模拟实现了一下comet, 不是真正的comet哦,因为不会有这样的应用场景, 只是模拟实现, 仅供参考.

一. 需求.

实现将服务端的时间推送到客户端, 客户端在得到服务端相应后将时间显示在页面上.

二.实现.

1开发框架: 用jsp+servlet的方法, 用了一个webframework框架, 自己写的, 类似于struts2, 可以的话就把它当作struts2来看吧.

2. 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>My JSP 'serverTime.jsp' starting page</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">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->
	<script type="text/javascript">
		var stop=false;
		var div= "";
		
		var inited = false;
		function init(){
			div = document.getElementById("forDisplay");
		}
		
		function stoped(){
			stop=true;
		}
		
		function started(){
			if(!inited){
				init();
				inited = true;
			}
			stop=false;
			clear();
			ajax();
		}
		function clear(){
			if(div){
				div.innerHTML="";
			}
		}
		
		function creatXHR(){
			var xmlhttp_request = "";
				
			  try{
				  	if( window.ActiveXObject ){
				  		for( var i = 5; i; i-- ){
				  			try{
					  			if( i == 2 ){
					  				xmlhttp_request = new ActiveXObject( "Microsoft.XMLHTTP" ); }
					  			else{
					  				xmlhttp_request = new ActiveXObject( "Msxml2.XMLHTTP." + i + ".0" );
					  				xmlhttp_request.setRequestHeader("Content-Type","text/xml");
					  				xmlhttp_request.setRequestHeader("Charset","gb2312"); }
					  			break;
							}
				  			catch(e){
				  				xmlhttp_request = false; 
							} 
						}
					}
				  else if( window.XMLHttpRequest ){ 
						xmlhttp_request = new XMLHttpRequest();
					} 
				}
			  catch(e){ 
					xmlhttp_request = false; 
				}
				return xmlhttp_request;
			}
		function ajax(){
			var xmlhttp_request = creatXHR();
		  xmlhttp_request.open('GET', 'ajax.action', true);
		  xmlhttp_request.send(null);
		  xmlhttp_request.onreadystatechange = function(){
			  if (xmlhttp_request.readyState == 4) {
					if(xmlhttp_request.status == 200){
					  var timeStr = xmlhttp_request.responseText;
					  div.innerHTML =timeStr+"<br/>"+div.innerHTML;
					}
					if(!stop){
						ajax();
					}
			  } 
		  }
  
		}
	</script>
  </head>
  
  <body>
  		<button value="start" onclick="started()">Start</button> <button value="stop" onclick="stoped()">Stop</button> <BR/>
    	<div id="forDisplay"></div>
  </body>
</html>

前面我有篇文章谈到, 客户端做的事情很简单, 就是提交ajax请求, 等待服务端返回数据, 展示完后继续请求即可. 我这里做了个控制, 可以自由停止.

3.服务端代码


package org.jiacheo.webframework.test;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

import org.jiacheo.web.framework.Template;
import org.jiacheo.web.framework.context.TemplateContext;

public class Time4Ajax implements Template {

	@Override
	public String execute() {
		try {
			PrintWriter writer =TemplateContext.getResponse().getWriter();
			Random random = new Random();
			int second = random.nextInt(10);
			iambusy(second);
			Date date = new Date();
			SimpleDateFormat format = new SimpleDateFormat("服务器时间是:yyyy年MM月dd日,HH时mm分ss秒");
			System.out.println(format.format(date));
			writer.println(format.format(date));
			writer.flush();
			writer.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		return null;
	}

	private void iambusy(int second) {
		// TODO Auto-generated method stub
		final int oneSecond = 1000;
		try {
			Thread.sleep(oneSecond*second);
		} catch (InterruptedException e) {
			//ignore it
		}
	}

}

每次请求都随机sleep几秒, 模拟在处理事务, 得到处理完了再返回数据, 也就是吧服务端的时间推送到客户端去.

这样就可以模拟comet的实现了. 但这里跟comet最大的不同是, 服务端不是主动主动阻塞的, 如何做到服务端主动阻塞, 等待有了返回结果再返回给客户端, 这个服务端实现的一个难点.我之前提到可以用时间模型, 但是事件模型能做的东西实在太少了, 要是能从规范上搞定, 那这个实现就方便很多了.

测试结果:

客户端显示:

服务器时间是:2010年11月25日,22时19分19秒 
服务器时间是:2010年11月25日,22时19分10秒 
服务器时间是:2010年11月25日,22时19分07秒 
服务器时间是:2010年11月25日,22时19分06秒 
服务器时间是:2010年11月25日,22时19分04秒 
服务器时间是:2010年11月25日,22时19分00秒 
服务器时间是:2010年11月25日,22时18分52秒 
服务器时间是:2010年11月25日,22时18分48秒 
服务器时间是:2010年11月25日,22时18分39秒 
服务器时间是:2010年11月25日,22时18分35秒 
服务器时间是:2010年11月25日,22时18分28秒 

服务端显示

服务器时间是:2010年11月25日,22时18分28秒
服务器时间是:2010年11月25日,22时18分35秒
服务器时间是:2010年11月25日,22时18分39秒
服务器时间是:2010年11月25日,22时18分48秒
服务器时间是:2010年11月25日,22时18分52秒
服务器时间是:2010年11月25日,22时19分00秒
服务器时间是:2010年11月25日,22时19分04秒
服务器时间是:2010年11月25日,22时19分06秒
服务器时间是:2010年11月25日,22时19分07秒
服务器时间是:2010年11月25日,22时19分10秒
服务器时间是:2010年11月25日,22时19分19秒

注意我故意将客户端倒过来显示的.  可以看到, 客户端和服务端的数据是完全一致的.

comet, 比想想中的要难搞多了, 我能不能做个框架出来搞定他?
关于comet 框架和服务器, 可以看看 APE(ajax push engine)

分享到:

2 条评论

昵称

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

  1. kensou97

    额这是轮询,不是推送吧…

    1. jiacheo

      你说的对, 早期文章,理解不够透彻,请见谅哈~