利用Response.Flush和iframe实现”服务器推”技术
通过在HTML页面里陷入一个隐藏的iframe,然后将这个iframe的src属性设为对一个长连接的请求(利用chunked传输response),服务器端就能源源不断地往客户推送数据。
基于流方式的”服务器推”模型:
服务端在接到客户端的请求时,通过Response的Flush()方法发送数据,可以使用定时器的方式发送数据,没有数据也发送”无数据”,让客户端保持长连接,直至客户端断开连接,请求结束。每次数据传送不会关闭连接,连接只会在通信出现错误时,或是连接重建时关闭(一些防火墙常被设置为丢弃过长的连接, 服务器端可以设置一个超时时间, 超时后通知客户端重新建立连接,并关闭原来的连接)。
实现代码:
页面Default.aspx,用来展示数据:
1: 数据列表:o<br />
2: <div id="con" style=" width:400; height:200px; border:1px solid #FF0">
3: </div>
4: <iframe id="flush" src="Flush.aspx" style=" display:none" />
5:
ifame的src对应的Flash.aspx后台代码,模拟后台发送数据:
1: protected void Page_Load(object sender, EventArgs e)
2: {
3: string startHTML = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" + Environment.NewLine
4: + "<html xmlns=\"http://www.w3.org/1999/xhtml\" >" + Environment.NewLine
5: + "<head>" + Environment.NewLine
6: + "</head>" + Environment.NewLine
7: + "<body>" + Environment.NewLine;
8:
9: startHTML += new String(' ', 1024) + Environment.NewLine;
10:
11: Response.Write(startHTML);
12: Response.Flush();
13:
14: string data = "<script type=\"text/javascript\">parent.$('#con').append(\"{0}\");</script>";
15: Response.Write(string.Format(data, "开始发送数据:<br/>"));
16: Response.Flush();
17:
18: int index = 0;
19: while (true)
20: {
21: System.Threading.Thread.Sleep(2000);
22: if (index % 2 == 0)
23: {
24: Response.Write(string.Format(data, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 服务端发送数据<br/>"));
25: }
26: else
27: {
28: Response.Write(string.Format(data, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 无数据发送<br/>"));
29: }
30: Response.Flush();
31:
32: index++;
33: }
34: }
35:
运行Default.aspx的结果:
使用 iframe 请求一个长连接有一个很明显的不足之处:IE、Morzilla Firefox 下端的进度栏都会显示加载没有完成,而且 IE 上方的图标会不停的转动,表示加载正在进行;刷新当前页面反应也是会很慢。
解决IE的进度栏显示加载没有完成,可以使用一个称为“htmlfile”的 ActiveX,是Google 的天才们使用的方法,该控件也被用到gmail+gtalk 产品中。
修改Default.aspx的页面代码:
1: 数y据Y列D表í:o<br />
2: <div id="con" style=" width:400; height:200px; border:1px solid #FF0">
3: </div>
4: <script type="text/javascript">
5: function getData(d)
6: {
7: $("#con").append(d);
8: }
9:
10: function rpc_iframe() {
11: var transferDoc = new ActiveXObject("htmlfile");
12: transferDoc.open();
13: transferDoc.write("<html>")
14: transferDoc.write("<div><iframe src=\"Flush.aspx\"></iframe></div>");
15: transferDoc.close("</html>");
16: transferDoc.parentWindow.getData = getData;
17: setInterval(function () { }, 10000); //不加这句会使连接断开
18: }
19:
20: rpc_iframe();
21: </script>
22:
修改Flush.aspx.cs代码:
1: //string data = "<script type=\"text/javascript\">parent.$('#con').append(\"{0}\");</script>";
2: string data = "<script type=\"text/javascript\">parent.getData(\"{0}\");</script>";
3:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)