65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET 和 Comet:重拾套接字

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (12投票s)

2008 年 4 月 9 日

CPOL

7分钟阅读

viewsIcon

159902

downloadIcon

2978

在 ASP.NET 中实现基于套接字的 Comet 解决方案。

Sample Image

引言

网页和 ASP.NET 是很棒的工具,但正如古老的谚语所说,“如果你只有一把锤子,看什么都像钉子”。ASP.NET 是一种 Web 技术,其存在的全部意义就是向请求它们的 Web 浏览器提供资源。这很棒,而且对于目前互联网上的绝大多数事物都有效。事实上,当人们想到互联网时,他们大多将其与无处不在的万维网模型或其 HTTP 协议联系起来。但是,如果我们想要更多……如果我们希望 Web 浏览器不仅仅是请求资源,而是能够主动将信息推送到它们,而无需先被请求呢?例如:实时维基、投票、聊天、股票行情自动收录器、实时拍卖和游戏。

这就是现有范式失效的地方,我们必须回归到更古老的技术,即互联网赖以建立的根基……是的,我说的就是真正的双向通信、交互性、*天哪*,套接字、TCP/IP!

退一步说,Web 请求大致可以比作学生向老师提问。然而,只有学生可以提问,老师不能主动向学生灌输事实。本文提出了一种打破这种模式的实验性方法。目前大多数解决方案,统称为 “Comet”,涉及 Web 浏览器与 Web 服务器保持活动的 HTTP 连接,就像学生始终吸引老师的注意力一样。本文介绍的是另一种方法,它利用“侧通道”,其中“老师”(即 Web 服务器)不必花费太多精力或资源来响应烦人的问题(Web 请求),我们可以改为推送信息,或者以更具交互性的方式进行交互。

背景

本文的灵感部分来源于 Alex MacCaw 的工作和代码,他是创建 Juggernaut 扩展到 Ruby on Rails 的开发者。但是,为什么要把所有乐趣都留给那些动态语言的人呢?我们不能在 ASP.NET 中也做到这一点吗?答案是“我们可以”。

如何在不先发起请求的情况下与 Web 浏览器通信?一种解决方案是让 Web 浏览器通过一个小巧轻便的 Flash 组件直接与服务器保持打开的套接字连接。

这种方法有什么好处?

  • 它消耗的 Web 服务器资源少得多。我们没有将任何 Web 服务器线程专门用于响应“长轮询”请求。
  • 它简单易于实现。
  • 良好的跨平台支持(任何支持 Flash 8 的现代 Web 浏览器,例如 IE、FireFox、Safari、Opera)。
  • 延迟更低,无需重新建立连接,也无需其他 HTTP 协议开销。

当然,它也有缺点

  • 我们需要在 Web 服务器或网络域上安装一些东西来接受这些套接字连接。
  • 连接到 Comet 服务器的嵌入式 Flash 组件将无法在阻止非 HTTP 端口的防火墙或代理后面工作。
  • 它需要 Web 浏览器启用 Flash 和 JavaScript。
  • 这是一种“hack”(尽管许多如今普遍存在的 Web 浏览器技术也可以这么说)。

Using the Code

Comet 应用程序可分为两类

  • “服务器推送”应用程序,其中 Web 服务器根据用户事件推送更新和更改信息,例如实时维基、投票、聊天等。
  • “交互式”应用程序,其中外部进程在响应事件时将信息推送到 Web 浏览器,例如股票行情自动收录器、实时拍卖、游戏等。

服务器推送

在服务器推送场景中使用 Comet 的工作流程是:

  1. Web 浏览器从 Web 服务器请求页面,该页面包含 Flash Comet 组件、Comet JavaScript 和唯一的身份验证字符串。
  2. Web 服务器将 Comet 连接与“Comet 服务器”注册,指定其通道、身份验证字符串以及任何初始状态。
  3. Web 浏览器打开到 Comet 服务器的套接字连接,并发送其身份验证字符串。
  4. Web 浏览器使用 postback 发送数据到 Web 服务器。
  5. Web 服务器响应任何 postback 或 AJAX 调用,并将任何更新发布到 Comet 服务器。
  6. Web 浏览器响应其 Comet 连接的任何更新。

在代码中,以一个简单的“留言簿”为例

  1. 将“CometControl”放置在 ASP.NET 网页上
  2. <CometControl
        id="cometControl"
        runat="server"
        channel="GuestBook"></CometControl>
  3. 注册 Comet 连接
  4. protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
            cometControl.Register();
    }
  5. 如果“AutoConnect”属性设置为 true(默认值),则 Web 浏览器会自动打开套接字连接。
  6. 可以使用简单的 UpdatePanel 和 ASP.NET AJAX 扩展执行 AJAX postback。
  7. Web 服务器响应 AJAX 事件,通过发布将在 Web 浏览器上自动评估的 JavaScript 代码。
  8. protected void submitButton_Click(object sender, EventArgs e)
    {
        string name = nameTextBox.Text.Trim();
        string text = commentTextBox.Text.Trim();
        if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(text))
        {
            cometControl.Data = "guestbook_addComment ("
                + Wxv.Comet.Utility.SerializeJSON(
                    HttpContext.Current.Server.HtmlEncode(name))
                + "," + Wxv.Comet.Utility.SerializeJSON(
                    HttpContext.Current.Server.HtmlEncode(text)) + ");";
            cometControl.Publish();
        }
        commentTextBox.Text = "";
    }
  9. 最后,Web 浏览器接收 Web 服务器上发布的数据并执行它
  10. guestbook_addComment = function(name, comment)
    {
        var commentsDiv = document.getElementById ("comments");
        var e = document.createElement("blockquote");
        e.innerHTML = comment + " - " + name + "";
        commentsDiv.insertBefore (e, commentsDiv.firstChild);
    }

交互式

交互式场景非常相似,但 Web 浏览器不再进行 postback 或 AJAX 调用到 Web 服务器,而是使用其 Comet 连接直接将数据发送到应用程序客户端,反之亦然。

在交互式场景中使用 Comet 的工作流程是:

  1. Web 浏览器从 Web 服务器请求页面,该页面包含 Flash Comet 组件、Comet JavaScript 和唯一的身份验证字符串。
  2. Web 服务器将 Comet 连接与“Comet 服务器”注册,指定其通道、身份验证字符串以及任何初始状态。
  3. Web 浏览器打开到 Comet 服务器的套接字连接,并发送其身份验证字符串,Comet 服务器会告知任何应用程序客户端是否已在它们订阅的通道上建立连接。
  4. 应用程序客户端将数据发送到 Comet 服务器,Comet 服务器将其传递给任何已在该通道上连接的 Web 浏览器。
  5. Web 浏览器通过其 Comet 连接将数据发送到 Comet 服务器,Comet 服务器将其传递给任何已订阅该通道的应用程序客户端。

Web 浏览器代码仍然非常相似,但现在,我们不再进行 AJAX 调用或 postback,而是可以通过 Comet 连接将数据发送到我们积极监听的应用程序客户端。

例如:响应“音乐播放器”应用程序中的按钮点击

function sounds_click(soundId)
{
    comet.send (soundId);
}

Comet 服务器和客户端

Comet 服务器是一个简单的事件处理和消息传递组件,它接受两种类型的连接:

  • 来自 Web 浏览器的 Comet 连接,这些连接总是预先注册并与单个通道关联。
  • 来自 Web 服务器、Comet 控件或应用程序客户端的客户端连接。

它响应以下客户端事件:

  • Register - 客户端希望允许 Web 浏览器建立 Comet 连接。
  • Subscribe - 客户端希望侦听特定通道上的事件。
  • Publish/Push - 客户端希望将数据发送到整个通道(Publish)或特定的 Comet 连接(Push)。

它向已订阅相关通道的任何客户端发送以下事件:

  • Connect - Web 浏览器已成功连接并向 Comet 服务器进行身份验证。
  • Disconnect - 已认证的 Web 浏览器已从 Comet 服务器断开连接。
  • Send - Web 浏览器已将数据发送到 Comet 服务器。

Comet 服务器和客户端组件(应用程序客户端可以基于此编写)都是简单的组件。Comet 服务器组件是独立的,唯一的交互需求是启动和停止它,它可以轻松地托管在 Windows 应用程序、服务,甚至 Web 服务器本身中。同样,客户端也是一个简单的组件(CometControl 已封装了它),它公开了一些简单的(在单个线程上)方法和事件,可以轻松扩展以编写您自己的应用程序客户端,这些客户端也可以以多种方式托管。

摘要

Web 浏览器向服务器打开套接字连接实际上并不是什么新鲜事。在它们孤立的小沙箱中,Java Applet 自发明十多年以来一直在这样做,Flash 也有此功能一段时间了。Microsoft 的 Silverlight 最终将在 2.0 版本中获得它。Comet 方法所做的就是直接在 Web 浏览器中实现类似的功能。

我通过这个项目玩得很开心,探索了 ASP.NET 的 Comet 解决方案。我不认为它比它本身更是什么,只是一个玩具项目;所以请带着一粒盐来消费和品尝它(如果味道不错,请注明出处)。然而,对作者来说,它提供了对可能性的有趣见解。

历史

  • 2008 年 4 月 7 日 - 第一个版本!
© . All rights reserved.