博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

推技术ActiveXobject("htmlfile") 长连接

Posted on 2012-11-01 15:16  bw_0927  阅读(2221)  评论(0编辑  收藏  举报

http://www.cnblogs.com/sweting/archive/2009/12/19/1627638.html

 

http://infrequently.org/2006/02/what-else-is-burried-down-in-the-depths-of-googles-amazing-javascript/

Gmail的Talk功能应用到了一个新的IE内置ActiveXObject :new ActiveXObject("htmlfile"), Alex Russell将这些体验背后的技术命名为Comet,他认为这种技术所创造的体验与Ajax所能做的已经有非常明显的区别,Comet通过让浏览器保持一个长时间活动的HTTP链接,实现了服务器与浏览器的快速数据交互,并且能够实现服务器PUSH,而Ajax则是在用户进行操作之后才调用服务器数据进行反馈

=========================

根据
http://alex.dojotoolkit.org/?p=538
以及Gmail Talk的一个开发人员的回应(http://pupius.co.uk/)

Gmail的Talk功能应用到了一个新的IE内置ActiveXObject :new ActiveXObject("htmlfile");
此ActiveXObject使得IE有了"安静的"与服务器端建立HTTP长连接的能力,使得服务器可以
主动向浏览器端Push数据,而不需要浏览器端反复向服务器端发出请求

与直接来个隐藏iframe读一个长连接相比这种做法在功能没区别
其主要的好处是这么新建一个htmlfile再把iframe写到里面,建立一个长连接时
IE就不会在下面的状态栏一直显示 "正在打开XXXXXXXXXXXXXXXX页面"

htmlfile就是一个COM版的DOM,也就是说,htmlfile是个ActiveX版的 window.document。

 

=========================

在以往的和服务器端通信技术中,我们多数使用的是AJAX轮询式访问,也就是在Javascript中控制时间间隔,然后每隔一段时间就访问一次服务器,然后获得数据或通知。但是这种轮询方式的访问有90%是在做无用功。

要想长时间保持服务器和浏览器之间的连接怎么办?长连接技术,这可不是什么新技术,用IFrame作为隐藏帧指向长请求页面的方法早已被很多人运用在互联网上,但是IFrame作为隐藏帧有一个弊端,那就是浏览器的进度条始终处在读取状态。为了使用户获得更好体验,“Google的天才们”使用了一个叫“htmlfile”的对象解决了这一问题,并把它运用了了GMail和GTalk两个产品上。

如今我们公司要做的新项目上要求有实时报警功能,本来我想用AJAX轮询做,但是觉得挺没追求的,前段时间听说有了Server Push,但是没仔细研究,这次倒是个机会,一天时间,从网上搜集资料。资料不是很多,而且现在有很多开发人员还认为长连接是天方夜谭,居然还有把HTTP协议搬出来要证明自己观点的……

废话不多说了,来介绍一下长连接技术,通常的长链接就是做一个网页,里面写好一个IFrame标签,高宽设置为0,SRC属性指向一个网页,比如是ASPX,然后在这个文件中不做别的,只是在调用Context.Response.Write方法,输出什么?比如客户端有一个更改时间的方法Change(time),那输出就是("<script>window.parent.Change("+DateTime.Now.ToString()+")</script>"),也就是不断的输出客户端的函数调用,并且做成死循环,这样浏览器和服务器端就形成了一条源源不断的数据传输链接。

那htmlfile是什么呢?这是一个类似Javascript中Window对象的一个ActiveXObject,它内部也是DOM结构,将作为隐藏帧的IFrame写入这个对象中,就可以解决进度条的问题。说的可能比较晦涩,来看实例代码吧:

Default.aspx.cs

c# 代码
 
public partial class _Default : System.Web.UI.Page    
{    
    protected void Page_Load(object sender, EventArgs e)    
    {    
   
    }    
   
    protected override void Render(HtmlTextWriter output)    
    {    
   
        string str;    
        while (true)    
        {//死循环保持长链接     
            str = "<script >window.parent.Change('" + DateTime.Now.ToLongTimeString() + "')</script>";    
            this.Context.Response.Write(str);    
            this.Context.Response.Flush();//输脚本调用出     
            System.Threading.Thread.Sleep(1000);    
        }    
    }    
}   
WebForm1.aspx

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Asp.net Server Push</title>

  <script type="text/javascript"> 
    function Change(str){ 
         window.document.getElementById("div1").innerText=str; 
    } 
    function onload(){ 
        var ifrpush = new ActiveXObject("htmlfile"); // 创建对象 
        ifrpush.open(); //打开
        var ifrDiv = ifrpush.createElement("div"); //添加一个DIV
        ifrpush.appendChild(ifrDiv); //添加到 htmlfile
        ifrpush.parentWindow.Change=Change; //注册 javascript 方法   搞不明白为什么还要注册
        ifrDiv.innerHTML = "<iframe src='Default.aspx'></iframe>"; //在div里添加 iframe
        ifrpush.close(); //关闭
    } 
    
     onload(); 
    </script>
</head>
<body> 
        <div style=" float:left">现在时间是:</div> 
        <div id="div1"></div> 
</body>
</html>

Default.aspx不需要做修改。

 

 

在IE下实现长链接还是依靠google那帮牛人的思想,利用ActiveXObject("htmlfile")来实现服务器端向客户端的push... 

而在FireFox下要实现长链接,则需要用到AJAX,用XMLHttpRequest()对象实例的readyState属性就可以达到push的效果,只要把readyState==3作为判断条件就可以在客户端实现长链接...这是我花了一天时间实现的功能,但是这个实现办法在效率上明显不如IE下的ActiveXObject("htmlfile"),不过本人也实在没别的途径了,只好先用了,等以后有更好的办法再替换~呵呵,谢谢帮我顶帖的朋友了哈哈,我再放一天吧,明天再结帖~希望有同样困惑的朋友能从我这个方法里得到启发~

==========================

 

===============

What else is burried down in the depth’s of Google’s amazing JavaScript?

So the new GTalk interface in GMail is pretty rad. Congrats to Dan and the rest of the team that made it “go”.

The talk feature is cool not just from a UI perspective as the code is also chock full of little gems. I’m kind of a dork about low-latency data transport to the browser. HTTP wasn’t meant to be used this way…so of course I’m interested! Ever since Joyce got me involved in the rewrite of mod_pubsub I’ve had my eye on the various ways that servers can push data to browsers and the kinds of technology that will prevent a server that’s doing this from melting down (hellooooooooo Twisted). Using just what’s available to the browser, it’s possible to have the server push data encapsulated in <script> blocks and rely on a progressive rendering behavior that every modern browser implements to dispatch events in near real-time (compared to full page refresh or polling delay). There are a mountain of browser quirks that of course play into this process. The least desirable of these to the user are the “phantom click” and the “throbber of doom” that afflict IE users.

When a page (or an iframe it hosts) is loading content, your browser usually shows some sort of “I’m working” indicator. In the bottom “taskbar” there is usually some sort of progress meter. In the upper right (on IE) the “throbber” will continue to animate until the work is done. Of course in the scenario I’m describing the sent page is never done. The whole point is that the server keeps the connection open. Combine this with the IE behavior of producing a “click” like sound when an iframe is navigated to a different URL, and you’ve got a pretty poor user experience.

But couldn’t you do something with XMLHTTP? Short answer: yes, but not as portably and it won’t get you around IE’s 2-connection limit either so there’s not much of a win. For the long answer, see my talk at ETech or wait for me to post the slides. At the end of the day, the hidden <iframe> hack scales best and is the most portable. Especially if you can lick the UX problems.

Which Google has.

How? By cleverly abusing another safe-for-scripting ActiveX control in IE. Here’s the basic structure of the hack:

  // we were served from child.example.com but 
  // have already set document.domain to example.com
  var currentDomain = "http://exmaple.com/"; 
  var dataStreamUrl = currentDomain+"path/to/server.cgi";
  var transferDoc = new ActiveXObject("htmlfile"); // !?!
  // make sure it's really scriptable
  transferDoc.open();
  transferDoc.write("<html>");
  transferDoc.write("<script>document.domain='"+currentDomain+"';</script>");
  transferDoc.write("</html>");
  transferDoc.close();
  // set the iframe up to call the server for data
  var ifrDiv = transferDoc.createElement("div");
  transferDoc.appendChild(ifrDiv);
  // start communicating
  ifrDiv.innerHTML = "<iframe src='"+dataStreamUrl+"'></iframe>";

This is the kind of fundamental technique that is critical to making the next generation of interactive experiences a reality. Server tools like mod_pubsub and LivePage (and perhaps even JMS buses) are starting to come into their own and the benefits of event-driven IO are starting to become well understood by server-side devs. It’s only a matter of time before server-push data hits an inflection point in the same way that background single-request/single-response data transfer did with Ajax. Dojo will, of course, have infrastructure to support this kind of thing when the borader developer community is ready (most if it is already in place).

From long and painful experience and amazingly deep respect, I take my hat off and bow to whoever it was on the GMail/GTalk team that figured this out. It’s a hell of a hack. It’s no wonder that Google has been able to attract and develop the best DHTML hackers in the world.

Update: so just to be *very* clear, I worked on the rewrite of the mod_pubsub *client*. The server rewrite was handled by some folks who are much smarter than I am.