zoukankan      html  css  js  c++  java
  • 服务器推技术研究Comet

    服务器推技术

    最近参与的一个关于股票的项目,有这样一个需求。服务器需要主动推送给客户端消息。这和传统的Web模式不同。传统的Web系统,客户端和服务器的交互是这样的:

    客户端先和服务器建立一个TCP连接,然后客户端开始发送数据,服务器端接受数据,并且根据请求去反馈相应的信息,然后服务器终止TCP连接。

    现在的HTTP1.1版本都默认Connection:keep-alive 。就是所谓的长连接,在服务器返回客户端信息之后,服务器端不会立刻断开连接,而是保持连接,直到服务器设定Timeout时间限制为止。当然keep-alive 要长期占用服务器的一个TCP 通道,占用服务器的资源。

    而对与一些HTTP1.0版本是不识别keep-alive的,所以设置了keep-alive是没有用的。在实际使用中,HTTP头部有了Keep-Alive这个值并不代表一定会使用长连接。


    那么如何使服务器和客户端保持长连接,让服务器接受到数据之后就立刻发送给客户端呢?

    一,使用ajax长轮询,与服务器保持长连接。

    二,使用iframe标签,后台不断输出代码到前端。

    三,webSocket方法。


    我总结了一下,大体上可以分为上面三类:

    1.ajax长轮询:

    实际上就是前端,不停连续的发送请求给后端,这样就可以保持前端和后端的连接了。当然,这种暴力的方式也分好和坏。如果你在前端里,写一个while循环,向后端发送ajax请求,那就是这样的情况,前一个请求,后端还没有处理完,另一个请求就发送过来了,请求不断的发送,有很多请求就被搁置,然后阻塞在那里直到自动关闭。这样是最消耗服务器资源的。当然我们可以改善一下:

    	$.ajax({
    		
    			url:'mydata',
    			dataType: 'json',
    			method:'post',
    			success:function(data){
    			//alert(data);
    			
    			$("#hi").append("姓名:"+data.name+"  性别:"+data.sex);
    			conn1();
    	
    			},
    			error:function(e){
    				conn1();
    			
    			}
    		});
    	

    这样的请求就变成,前端发送了请求,直到有数据从后端传送过来,我才继续发送请求。或者我的请求一直在搁置,或者发生错误了,我再发送请求。这样的话就大大减少了前端向后端发送请求的次数,比暴力循环优化了很多。

    2.iframe 长连接。

    其实iframe标签,可以理解为文档中的文档,就是在html页面中,iframe来执行后端传过来的代码,相当于在html中嵌入一段需要执行的代码。那么利用iframe这个标签,我们可以这样实现长连接。

    前端发送一个请求到后端,后端然后开一个循环,不断的向前端的iframe中输出代码,然后iframe执行这段代码,来输出信息。

    这里就不想写代码了。

    其实这两种方式,前者是让前端死循环,后者是让后端死循环。后端的话,当然可以去开一个线程执行死循环。


    3.webSocket

    是一种新技术,在客户端和服务器端建立Socket连接,这样前端需要安装flash去执行Socket。这样的方式,前后端可以随心所欲传送数据。网页游戏就是这种方式。

    接下来重点介绍Pushlet 框架。


    Pushlet框架,百度上说,用了ajax轮询和iframe隐藏帧两种方式实现了服务器推技术。


    https://github.com/SilentCC/MyProgramming/blob/master/README.md

    我的Git中的WebComet中有源码。下面来看下如何使用。

    可以看到目录结构是这样的

    我们需要pushlet.jar    log4j.properties   pushlet.properties    sources.properties    和aja-pushlet-client.js 这四个文件,在源代码包里都有。


    我们需要再web.xml中配置文件

       <servlet>  
            <servlet-name>pushlet</servlet-name>  
            <servlet-class>nl.justobjects.pushlet.servlet.Pushlet</servlet-class>  
            <load-on-startup>3</load-on-startup>  
        </servlet>
        
         <servlet-mapping>  
            <servlet-name>pushlet</servlet-name>  
            <url-pattern>/pushlet.srv</url-pattern>  
        </servlet-mapping>

    然后开始写pushlet的核心类

    package com;
    
    import java.io.Serializable;
    import java.io.UnsupportedEncodingException;
    import sun.rmi.runtime.Log;
    import nl.justobjects.pushlet.core.Dispatcher;
    import nl.justobjects.pushlet.core.Event;
    import nl.justobjects.pushlet.core.EventPullSource;
    import nl.justobjects.pushlet.*;
    import nl.justobjects.pushlet.core.EventSource;
    
    public class HelloWorldPushlet implements Serializable{
    	
    	static public class HwPlushlet extends EventPullSource{
    		
    		protected long getSleepTime(){
    			
    			return 3000;
    		}
    		
    		public Event pullEvent(){
    			
    			Event event = Event.createDataEvent("/cuige/he");
    			event.setField("mess", "hello,world!Plushlet!");
    			//System.out.println("ok");
    			return event;
    		}
    		
    		
    	}
    	
    	static public class HsPlushlet implements EventSource{
    		
    		public void pullEvent(String message){
    			
    			Event event = Event.createDataEvent("/suige/he");
    			event.setField("mess", message);
    			Dispatcher.getInstance().multicast(event);
    		}
    
    		public void activate() {
    			// TODO Auto-generated method stub
    			
    		}
    
    		public void passivate() {
    			// TODO Auto-generated method stub
    			
    		}
    
    		public void stop() {
    			// TODO Auto-generated method stub
    			
    		}
    		
    	}
    	
    static public class HsPlushlet2 implements EventSource{
    		
    		public void pullEvent(String message){
    			
    			Event event = Event.createDataEvent("/cuige/he");
    			event.setField("mes", message);
    			Dispatcher.getInstance().multicast(event);
    		}
    
    		public void activate() {
    			// TODO Auto-generated method stub
    			
    		}
    
    		public void passivate() {
    			// TODO Auto-generated method stub
    			
    		}
    
    		public void stop() {
    			// TODO Auto-generated method stub
    			
    		}
    		
    	}
    	
    	
    
    }
    

    上面这个类是我们自己写的pushlet 的核心类。

    在类中,我们有两种方式可以向前端发送信息:

    1.继承EventPullSource 类,

    在子类中,我们可以设置getSleepTime() 来设置服务器每隔多长时间发送一组数据到前端。

    pullEvent是传播数据的方法,在子类中不能有参数


    2.实现EventSouce 接口。

    pullEvent可以传入参数。实现EventSouce的类,可以在服务器端任何需要的地方去使用~,这样的话我们可以在需要的时候传入需要的参数,然后再发送数据到前端

    创建event

    Event event = Event.createDataEvent("/cuige/he"); 
    event.setField("mes", message);
    广播event

    			Dispatcher.getInstance().multicast(event);

    这样在需要的地方定义类对象,再调用就好了

    在前端的话我们可以:

    <script type="text/javascript" src="ajax-pushlet-client.js"></script>
    	<script type="text/javascript">
    	
    	
    		function conn2(){
    	
    		PL._init();
    		
    		
    		
    		PL.joinListen('/suige/he');
    		alert("ok");
    		}
    	
    		
    		function onData(event){ 
    		
    		alert("ok");
    		var data =JSON.parse(event.get("mess"));
    		
    		$("#hi2").append("姓名:"+data.name+"性别:"+data.sex);
    		
    		
    		}
    		
    	</script>

    PL._init() 是初始化客户端,

    PL.joinListen('/suige/he') 是告诉高科端监听哪个event.

    function onData(event){} 就是接受数据的函数。


    这里我们还要配置数据源,根据我们写的主类,在sources.properties  中设置

    source1=com.HelloWorldPushlet$HsPlushlet
    source2=com.HelloWorldPushlet$HsPlushlet2

    这样的话,我们在一个界面只能监听一个全局的消息。怎么在一个界面的两个地方接受不同的数据源呢?
     

  • 相关阅读:
    sharepoint获取通用路径
    Sharepoint 在网站中创建用户组并添加权限
    ERP失败案例启示录:人是最关键的
    人生主要过渡期
    Windows Server 2012虚拟化性能及十大重要功能
    抢先看:iPhone5整机完整亮相
    未来五年10大关键IT趋势
    [转]完善的资产管理:实现以可靠性为中心的维护管理
    如何摆脱ERP困局
    项目经理的“七宗罪”
  • 原文地址:https://www.cnblogs.com/dacc123/p/8228516.html
Copyright © 2011-2022 走看看