Web页面实时刷新技术探讨

转载 2015年09月22日 11:52:38

一、总述

随着网络技术的飞速发展,使用B/S结构来实现项目应用已经越来越多,而实时监控一直都是多数行业软件所必备的功能,由此使用Web页面来实现实时监控成了一种必然的需求。

 

二、实时刷新技术

1、传统的页面刷新方式

传统的页面刷新方式很多,常见的有页面间隔一定的时间自动刷新、ActiveX控件、Applet等。

采用页面间隔一定的时间自动刷新的方式,是在网页的头部加入一下代码:

<meta http-equiv="refresh" content="20;url=newPage">

这里是经过20秒跳转到一个新页面,可以将“newPage”设置为本页面即为刷新本页面,刷新间隔时间可以修改“20”为任意时间。通过这种方式如果并发和访问量较大,服务器就有可能承受不了这种压力,从而造成服务器死机。

使用ActiveX控件的方式需要每个客户端下载安装ActiveX控件,并且客户端浏览器只能使用Windows的IE浏览器。

同样使用Applet需要客户端安装Java运行时。

这些传统的页面刷新方式都或多或少的存在着一些确定,在Web项目应用中的使用也越来越少。

 

2、Ajax轮询

Ajax轮询方式是使用客户端脚本,通过XMLHttpRequest来定时发送请求,从而查询页面数据的更新情况。通过这种方式,程序实现方便简捷,但客户端频繁的发送请求会给服务器带来很大的压力和客户端处理器负载,如果服务器端没有更新时,这种轮询访问服务器便是无意义的,并且耗费了网络资源与CPU处理资源。

实例说明:服务器端通过手动控制按钮产生一张图片,客户端显示最新图片及图片的信息内容。

服务器端通过一个按钮btnGet产生图片,按钮事件代码如下所示。

代码清单1:

protected void btnGet_Click(object sender, EventArgs e)

{

    //通过改写一张父图片上的文字来产生新图片

    System.Drawing.Image image = System.Drawing.Image.FromFile(HttpContext.Current.Server.MapPath("parent.jpg"));

    string currTime = System.DateTime.Now.ToString("yyMMddHHmmssffffff");

 

    Graphics g = Graphics.FromImage(image);

    g.DrawImage(image, 0, 0, image.Width, image.Height);

    g.DrawString(currTime, new Font("Arial", 28), new SolidBrush(Color.Red), 10, 10);

    g.Dispose();

 

    string savePath = "Pic/" + currTime + ".jpg";

    image.Save(HttpContext.Current.Server.MapPath(savePath));

 

    //将最新图片文件名写入到XML文件中

    XmlDocument xmlDoc = new XmlDocument();

    xmlDoc.Load(HttpContext.Current.Server.MapPath("newPic.xml"));

    XmlNodeList nodeList = xmlDoc.SelectSingleNode("Items").ChildNodes;

 

    XmlElement element = (XmlElement)nodeList[0];

    element.SetAttribute("code", currTime);

    xmlDoc.Save(HttpContext.Current.Server.MapPath("newPic.xml"));

}

显示图片页面通过两个页面分别显示图片信息与图片内容,显示图片页面内容如下所示。

代码清单2:

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title></title>

    <meta http-equiv="Content-Type" content="text/html; Charset=gb2312" />

    <script type="text/javascript">

        var xmlHttp;

        function CreateXMLHttp() {

            if(window.XMLHttpRequest) {

                xmlHttp = new XMLHttpRequest();

            }

            else if (window.ActiveXObject) {

                try { xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); }

                catch(e) {

                    try { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); }

                    catch(e) { }

                }

            }

            xmlHttp = new ActiveXObject("Msxml2.XMLHTTP.5.0");

        }

 

        function startXMLHttp() {

            CreateXMLHttp();

            xmlHttp.onreadystatechange =retDeal;

            xmlHttp.open("post","imgInfo.aspx",true);

            xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded charset=gb2312");

            xmlHttp.send();

        }       

     

         function retDeal() {

           if(xmlHttp.readystate==4) {

             if(xmlHttp.status==200) {

               hid1.value = xmlHttp.responseText;

               if(hid1.value != hid2.value) {

                 hid2.value = hid1.value;

                 ifrImg.location.reload();

                 document.getElementById("Content").innerHTML = hid1.value;

               }

             }

             setTimeout(startXMLHttp,2000);

          }

        }

    </script>

</head>

<body onload='Javascript:startXMLHttp()'>

    <div></div>

    <span id="Content"></span>

    <input type="hidden" id="hid1" /><input type="hidden" id="hid2" />

    <iframe id="ifrImg" src="img.aspx" width="800" height="500"></iframe>

</body>

</html>

 

3、DWR服务器Push

DWR的反转AJAX功能允许我们从服务器端来控制客服端,而不需要客户端的请求,服务器可以自动把消息发给指定的客户端。DWR的Push技术是让服务器每次发送广播时,把这个广播推送给客户端,而不用客户端去刷新,DWR的推送是基于长连接的,性能优越。

以服务器端通过手动控制按钮产生一张图片,客户端显示最新图片及图片的信息内容作为实例加以说明。

服务器端通过一个按钮产生图片,页面代码如下所示。

代码清单3:

<%@ page language="java" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

<title></title>

<script type='text/javascript'src='<%=request.getContextPath()%>/dwr/interface/getPic.js'></script>

<script type='text/javascript' src='<%=request.getContextPath()%>/dwr/engine.js'></script>

<script type='text/javascript' src='<%=request.getContextPath()%>/dwr/util.js'></script>

<script type="text/javascript">

    Date.prototype.format = function(format) {

    var o = {

        "M+" : this.getMonth()+1, //month

        "d+" : this.getDate(),    //day

        "h+" : this.getHours(),   //hour

        "m+" : this.getMinutes(), //minute

        "s+" : this.getSeconds(), //second

        "q+" : Math.floor((this.getMonth()+3)/3), //quarter

        "S" : this.getMilliseconds() //millisecond

        }

    if(/(y+)/.test(format)) format=format.replace(RegExp.$1,

        (this.getFullYear()+"").substr(4 - RegExp.$1.length));

    for(var k in o)if(new RegExp("("+ k +")").test(format))

        format = format.replace(RegExp.$1,

            RegExp.$1.length==1 ? o[k] :

                ("00"+ o[k]).substr((""+ o[k]).length));

    return format;

    }

 

    function getNewPic() {

        var currTime = new Date().format("yyMMddhhmmssS");

        var currPath = "D:/Program/Java/JavaSpace/ajaxTest/WebContent/";

       getPic.createStringMark(currPath+"parent.jpg",currTime,currPath+"Pic/"+currTime+".jpg");

        getPic.getNewPicId(currTime);

        }

</script>

</head>

<body>

    <input type="button" value="产生新图片" onclick="getNewPic();" />

</body>

</html>

显示图片页面通过两个页面分别显示图片信息与图片内容,显示图片页面内容如下所示。

代码清单4:

<%@ page language="java" pageEncoding="UTF-8"%>

<jsp:useBean id="aGetNewPic" scope="page" class="com.getNewPic" />

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

<title></title>

<script type='text/javascript'src='<%=request.getContextPath()%>/dwr/interface/getPic.js'></script>

<script type='text/javascript' src='<%=request.getContextPath()%>/dwr/engine.js'></script>

<script type='text/javascript' src='<%=request.getContextPath()%>/dwr/util.js'></script>

<script type="text/javascript">

    function init() {

        dwr.engine.setActiveReverseAjax(true);    //激活反转

        }

    window.onload = init;//页面初始化方法

    function refreshImg() {

        ifrImg.location.reload();

        }

</script>

</head>

<body>

    <div style=" float:left">最新图片:</div>

    <span id="divNewPicId"><%= aGetNewPic.currPicId %></span>

    <iframe id="ifrImg" src="img.jsp?id=<%= aGetNewPic.currPicId %>" width="800"height="500"></iframe>

</body>

</html>

另外,getNewPic类用于产生新图片、Push处理。

代码清单5:

public class getNewPic {

      

       public static String currPicId = "100413101427820";

      

       public String getNewPicId(String picId, HttpServletRequest request){

              if(currPicId == picId)return currPicId;

              if(picId != null) currPicId = picId;

             

              //获得DWR上下文

              ServletContext sc = request.getSession().getServletContext();

              ServerContext sctx = ServerContextFactory.get(sc);

              //获得当前浏览 client.jsp 页面的所有脚本session

              Collection sessions = sctx.getScriptSessionsByPage("/ajaxTest/client.jsp");

              Util util = new Util(sessions);

              //处理这些页面中的一些元素

              util.setValue("divNewPicId", currPicId);

              util.addFunctionCall("refreshImg",null);

             

              return currPicId;

       }

      

       public boolean createStringMark(String filePath,String markContent,String savePath)

       {

           ImageIcon imgIcon=new ImageIcon(filePath);

           Image theImg =imgIcon.getImage();

           int width=theImg.getWidth(null);

           int height= theImg.getHeight(null);

           //System.out.println(theImg);

           BufferedImage bimage = new BufferedImage(width,height, BufferedImage.TYPE_INT_RGB);

           Graphics2D g=bimage.createGraphics();

           g.setColor(Color.red);

           g.setBackground(Color.white);

           g.drawImage(theImg, 0, 0, null );

           g.setFont(new Font("Arial",Font.PLAIN,28)); //字体、字型、字号

           g.drawString(markContent,10,10); //画文字

           g.dispose();

           try

           {

                  FileOutputStream out=new FileOutputStream(savePath); //输出文件名

                  JPEGImageEncoder encoder =JPEGCodec.createJPEGEncoder(out);

                  JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bimage);

                  param.setQuality(1, true);

                  encoder.encode(bimage, param);

                  out.close();

              }

           catch(Exception e)

           { return false; }

           return true;

       }

 

}

 

4、与服务端建立长连接

与服务器建立长连接,也就是在显示数据页面中嵌入一个隐藏页面,该隐藏页面主要完成取服务器端所要显示的数据,并且将该页面显示数据的方法写成一个死循环,以此来保持与服务器端的长连接。

同样以服务器端通过手动控制按钮产生一张图片,客户端显示最新图片及图片的信息内容作为实例加以说明。

服务器端通过一个按钮btnGet产生图片,按钮事件代码同代码清单1。

显示图片页面通过两个页面分别显示图片信息与图片内容,显示图片页面内容如下所示。

代码清单6:

<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">

    <title></title>

<script type="text/javascript">

    function writePicInfo(str) {

        if (window.document.getElementById("divNewPicId").innerText != str) {

            window.document.getElementById("divNewPicId").innerText = str;

            ifrImg.location.reload();

        }

    }

    function onload(){

        var ifrpush = new ActiveXObject("htmlfile"); // 创建对象

        ifrpush.open();

        var ifrDiv = ifrpush.createElement("div"); //添加一个DIV

        ifrpush.appendChild(ifrDiv); //添加到htmlfile

        ifrpush.parentWindow.writePicInfo = writePicInfo; //注册javascript方法

        ifrDiv.innerHTML = "<iframe src='getNew.aspx'></iframe>"//在div里添加iframe

        ifrpush.close();

    }

     onload();

    </script>

</head>

<body>

        <div style=" float:left">最新图片:</div>

        <div id="divNewPicId"></div>

        <iframe id="ifrImg" src="img.aspx" width="800" height="500"></iframe>

</body>

</html>

其中,隐藏页面getNew.aspx代码如下所示。

代码清单7:

protected override void Render(HtmlTextWriter output)

{

    string str;

    while (true)  //死循环保持长链接

    {

        //读取最新图片信息

        XmlDocument xmlDoc = new XmlDocument();

        xmlDoc.Load(HttpContext.Current.Server.MapPath("newPic.xml"));

        XmlNodeList nodeList = xmlDoc.SelectSingleNode("Items").ChildNodes;

        XmlElement element = (XmlElement)nodeList[0];

        string newPicId = element.GetAttribute("code");

 

        str = "<script >window.parent.writePicInfo('" + newPicId + "')</script>";

        this.Context.Response.Write(str);

        this.Context.Response.Flush();

        System.Threading.Thread.Sleep(2000);

    }

}

代码中的“htmlfile”是一个类似JavaScript中Window对象的一个ActiveX Object,它内部也是DOM结构,将作为隐藏帧的IFrame写入这个对象中,这样可以解决进度条一直为读取状态的问题。

 

5、RTMP协议传输

随着网络技术的迅猛发展,视频、音频等多媒体通信需求越来越多,Adobe公司开放了RTMP(the Real-time Messaging Protocol)协议规范,RTMP协议作为客户端和服务器端的传输协议,这是一个专门为高效传输视频、音频和数据而设计的TCP/IP 协议。其优秀产品Flex是用于构建和维护在所有主要浏览器、桌面和操作系统一致地部署的极具表现力的 Web 应用程序的高效率的开放源码框架。

从目前的应用来说,RTMP主要用于音、视频的传输,流视频服务器就是FMS(Flash Media Server),其原称为FCS(Flash Communication Server),技术范畴能应用到诸如Flash聊天室、视频会议等领域。

以一个实现聊天功能的Flex程序为例,显示聊天内容代码如下所示。

代码清单8:

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" fontSize="12" creationComplete="init()">

 

<mx:Script>

    <![CDATA[

   

    import vo.Message;

    import mx.collections.ArrayCollection;

    import mx.controls.Alert;

   

    private var myNetConnection:NetConnection;  //flex fms 链接用的对象

    private var serverApp:String ="rtmp://127.0.0.1/Test";

    private var talk_so:SharedObject;  //fms 下的SharedObject 对象

      

    private function init():void

    {

       btn_send.addEventListener(MouseEvent.CLICK,btnSenClickHandler);

       myNetConnection = new NetConnection();

       myNetConnection.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler);   

       myNetConnection.connect(serverApp);

    }

   

    private function netStatusHandler(evt:NetStatusEvent):void

    {

       trace(evt.info.code);  //调试代码用     

       if ( evt.info.code =="NetConnection.Connect.Success" )

       {

           talk_so = SharedObject.getRemote("talk",myNetConnection.uri,true);

           talk_so.addEventListener(SyncEvent.SYNC,talkSoSyncHandler);

           talk_so.connect(myNetConnection);

       }

       else

       {

           Alert.show("链接失败"+evt.info.code);

       }

    }

   

    private function talkSoSyncHandler(evt:SyncEvent):void

    {

       txt_content.text="";

       if ( talk_so.data.msgList!=null )

       {

           var tmp:ArrayCollection = new ArrayCollection();

           convertArrayCollection(tmp,talk_so.data.msgList as ArrayCollection);        

           for(var i:int=0;i<tmp.length ;i++)

           {

              var message:Object = tmp.getItemAt(i);          

              varfullMsg:String=message.nickname+""+message.time.toTimeString()+":"+message.msg;          

              txt_content.text=txt_content.text+fullMsg+"/n";

           }

       }

    }

      

    private function btnSenClickHandler(evt:MouseEvent):void

    {

       var arr:ArrayCollection = new ArrayCollection();    

       if ( talk_so.data.msgList==null )

       {

           arr = new ArrayCollection();   

       }

       else

       {

           convertArrayCollection(arr,talk_so.data.msgList as ArrayCollection);

       }     

       var obj:Message = new Message();

       obj.nickname=txt_nickname.text;

       obj.msg=txt_message.text;

       obj.time = new Date();     

       arr.addItem(obj);   

       talk_so.setProperty("msgList",arr);

       /*将你更新好的聊天记录列表写入到公共的SharedObject对象中去即可。

           调用setProperty() 以更改数据对象的属性。 服务器将更新这些属性,并调度 sync 事件,并将这些属性发回到连接的客户端。*/

       txt_message.text="";

    }

   

    //交换数组中元素

    private functionconvertArrayCollection(arrNew:ArrayCollection,arrOld:ArrayCollection):void

    {

       arrNew.removeAll();     

       for(var i:int=0;i<arrOld.length ;i++)

       {

           arrNew.addItemAt(arrOld.getItemAt(i),i);

       }

    }     

    ]]>

</mx:Script>

 

    <mx:TextArea x="33" y="10" height="159" width="366" id="txt_content"/>

    <mx:TextInput x="33" y="177" width="62" id="txt_nickname"/>

    <mx:Label x="103" y="179" text=""/>

    <mx:TextInput x="146" y="177" width="185" id="txt_message"/>

    <mx:Button x="334" y="177" label="send" id="btn_send"/>

   

</mx:Application>

 

三、结语

从目前实际应用来说,以上四种实现Web页面实时刷新都是可行方案,各有优缺点与适用的具体环境。

Ajax轮询方式比较适用于需要传输的数据量较小的情况,可通过客户端首先轮询服务器端的更新标识,若有更新再下载更新数据,这样能减小一部分服务器的压力。

DWR反转AJAX功能,真正实现了从服务器端将更新“推”到客户端。

与服务器端建立长连接的方式,也是通过客户端的请求获取更新数据的。

通过RTMP协议传输,主要适用于音、视频的数据传输,比较适用于视频聊天室,目前视频服务器FMS的费用较高(4500元100个客户端),与服务器的连接数受到限制。

总体来看,要实现Web页面的实时刷新,肯定是会给服务器带来一定的压力的,对于具体项目的不同需求,可选择合适的方式来实现Web页面的实时刷新。

相关文章推荐

JS之页面自动刷新,用于需要实时更新页面

自动刷新页面的方法: 1.页面自动刷新:把如下代码加入区域中 其中20指每隔20秒刷新一次页面. 2.页面自动跳转:把如下代码加入区域中 其中20指隔20秒后跳转到http://www.xx...

利用javaScript实现时间实时更新

话不多说,贴代码,有什么不足的地方请告诉我,谢谢!或者有什么不懂得地方可以留言 function getTime(){ str = "当前时间为:" var p = document.getEl...

使用HighCharts实现实时数据展示

使用HighCharts实现实时数据展示   2012-12-01 13:42:58|  分类: JSP/JAVA技术 |  标签:highcharts  趋势图  曲线图  实时  工业控制 ...

Web页面实时刷新技术探讨

一、总述 随着网络技术的飞速发展,使用B/S结构来实现项目应用已经越来越多,而实时监控一直都是多数行业软件所必备的功能,由此使用Web页面来实现实时监控成了一种必然的需求。   二、实时刷新技术...

使用HighCharts实现实时数据展示

在众多的工业控制系统领域常常会实时采集现场的温度、压力、扭矩等数据,这些数据对于监控人员进行现场态势感知、进行未来趋势预测具有重大指导价值。工程控制人员如果只是阅读海量的数据报表,对于现场整个态势的掌...
  • gzh0222
  • gzh0222
  • 2014年04月26日 16:59
  • 16207

gotty - 基于Web的实时终端展示方式

需求考虑这样一种教学场景:老师通过终端演示编程,学生通过浏览器观看老师的每一步动作。方案 1 - tmux 通过 socket 共享 session。方案 2 - gotty...
  • maray
  • maray
  • 2016年11月07日 11:03
  • 2120

spring websocket让页面实时获取数据

1,依赖包加上 org.springframework spring-websocket ...
  • zxw394
  • zxw394
  • 2016年08月31日 17:49
  • 3036

Web页面实时刷新技术探讨

原文地址:http://blog.csdn.net/anluo_sun/article/details/48652215 一、总述 随着网络技术的飞速发展,使用B/S结构来实现...

Java后台实时输出数据到页面

当然,这个专业的有保持长链接,服务器推送等实现,这里需求较简单,不讨论。 做了个小功能,希望前台可以看到后台的实时处理进度,首先想到的就是能够在页面像后台打印日志一样的输出, 如下代码: ...

WebSocket 实时更新mysql数据到页面

使用websocket的初衷是,要实时更新mysql中的报警信息到web页面显示 没怎么碰过web,代码写的是真烂,不过也算是功能实现了,放在这里也是鞭策自己,web也要多下些功夫准备工作先看看my...
  • Nougats
  • Nougats
  • 2017年07月18日 15:16
  • 1631
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Web页面实时刷新技术探讨
举报原因:
原因补充:

(最多只允许输入30个字)