切削刃

长轮询和 SignalR

Dino Esposito

 

Dino Esposito
我们正在建立顶部的一种协议,,矛盾的是,构思和为多简单形式的互动设计更复杂的 Web 应用程序。HTTP 有没有内置的状态或甚至安全支持。其基本的假设是,客户端的请求放和 Web 服务器发出的响应。总括而言,这意味着没有请求,没有响应。

鉴于当前渗透和无处不在的 Web 解决方案,更改 Web (HTTP、 HTML、 JavaScript) 的支柱是 web 的出问题。但我们应该考虑改善这些支柱的一些呢?当然。现代应用程序具有更大限度推动 Web 协议和语言的特定要求 — 或超越。

此列的最近分期付款,讨论了手工的执行的一种机制,轮询服务器,并向客户端报告的更改。上个月,我实现使用的新兴的图书馆服务相同的想法 — SignalR。现在我将提供技术的简要概述和你今天的选项的摘要。我把 SignalR 放在聚光灯下,看看其执行 — 和一些它的魔力。

轮询注意事项

由于 HTTP 请求/响应约束,轮询是设置客户端和 Web 服务器之间的实时通信的唯一可能的方法。在方便的时候,客户端将推送请求,服务器将认真答复。投票的效能评估的关键是将分配给"在其方便。"表达的实际意义任何基于轮询的解决方案的核心总是有一个客户端请求。请求站直到服务器已回复。任何挂起的请求消耗浏览器连接,并且更重要的是,从事服务器线程,使这种宝贵的资源不可用的其他请求。总括来说,太频繁请求的 Web 服务器上生成压力。

但是不处理可扩展性的整体理念的越来越多的请求的服务器的能力吗?事实上,轮询并不创建新的可伸缩性问题,但它确实提供了大量的新请求必须考虑到,以确保可扩展性和高性能的服务器的服务器。让我们看看如何,我们可能会实现轮询。

AJAX 投票

在我 2011 年 12 月 (msdn.microsoft.com/magazine/hh580729) 和 2012 年 1 月 (msdn.microsoft.com/magazine/hh708746) 的列,我提出了一个框架,用于控制远程操作的进度。整个架构基于 AJAX 调用。第一,在客户端调用服务器终结点,开始可能非常长的任务 ; 下一步,它设置了一个计时器来放置到另一个终结点的并发调用每 500 毫秒。服务器任务完成其工作,它将更新的已知的位置。找到客户端服务器终结点,并定期援引只需检查该位置中的数据并返回任何内容。

这种 AJAX 轮询模式运行得漂亮,许多行业方案中广泛采用。大多数的网站提供新闻更新或比分直播按照这种模式。在我的文章,我只被适应要监测远程操作的进度的特定情况下的模式。

最后,AJAX 投票的问题搞清楚的正确的刷新间隔 — 一个代表在服务器上的压力和信息的准确性之间良好的平衡报告给用户。有效的 AJAX 投票解决方案可以使具体的含义,以"在客户端的方便"中发送请求。

长轮询

前 AJAX,开发人员用 meta 刷新的 HTML 标记,指示浏览器刷新页面每个给定的秒数。AJAX 投票,与您实现同样的东西,但在更平滑的方法。

为越来越多的应用程序,但是,这种形式是投票的不够的。AJAX 投票几乎不可避免地引入了服务器上的事件的发生和事件通知的客户端之间的延迟。通过调整更新频率,你可以算出很好的解决方案,但 AJAX 投票不能提供很多 (主要是社会) 应用程序似乎今天需要那一贯的和持续的连接。

这些天似乎是长轮询的解决方案。奇怪的是,AJAX 年前出现的更聪明的 AJAX 投票取代长轮询因为后者不是非常有效地在 Web 上)。长时间轮询是关于在 Web 上做同样的事情你做桌面的方案中。长轮询,地方请求的客户端和服务器没有回复,直到其返回的信息。Web 客户端保留挂起的连接被关闭时,才可以返回一些有效的响应。这正是现在要 — 只是减速的 Web 服务器的潜力。

长时间轮询数量较少的 AJAX 投票,相比的服务器的请求,但每个请求可能需要更长时间。随着时间推移,这可不利于健康的 Web 服务器因为它使从事直到可以生成响应的服务器线程。较少工作线程可用在给定的时间,Web 服务器不可避免地在它对任何其他请求的响应速度较慢的获取接收。要有效,长时间轮询需要一些严重的实施工作和先进的多线程和并行编程技巧。因此,多年来,长时间轮询其实不是一个选项,但这不重要,因为没有连续连接的需求。

今天,与 microsoft 的任务并行库。NET 框架 4 和其它设施在 ASP 中。构建异步 HTTP 处理程序,长轮询网已成为一个可行的选择。总体来说,手工制作长轮询框架是比相应的 AJAX 轮询框架仍难。您需要一个设计良好的服务器环境,不征税的 Web 服务器和客户端的环境,可以支持长轮询。长时间轮询,事实上,指开发通过 Web 和一定在经典的 HTTP 请求/响应数据包数的宏客户端/服务器操作。客户端必须足够聪明,重新发出立即的新请求,直到宏操作将终止。我稍后会回到这点。

拯救 SignalR

SignalR 是一个专门设计,以便实时的客户端/服务器通信的 Microsoft 框架。它提供了有效执行长轮询,不在服务器上,有很深的影响和在同一时间可确保有关远程会适当地更新客户机。图 1显示的代码,我提出了我最后一列中的摘录。BookingHub 类是您从 Web 浏览器启动"预订航班"的宏操作调用的方法

图 1 SignalR 类,它执行多步操作

public class BookingHub : Hub
{
  public void BookFlight(String from, String to)
  {
    // Book first leg
    Clients.displayMessage(
      String.Format("Booking flight: {0}-{1} ...", from, to));
    BookFlightInternal(from, to);
    // Book return
    Clients.displayMessage(
      String.Format("Booking flight: {0}-{1} ...", to, from));
    BookFlightInternal(to, from);
    // Book return
    Clients.displayMessage("Charging credit card ...");
    ChargeCreditCardInternal();
    // Some return value
    Clients.displayMessage("Flight booked successfully.");
  }
}

这显然是一个多步骤的操作,并为每个步骤类将通知发送到客户端。 涉及多少 HTTP 请求? 让我们看看与小提琴手 (请参阅图 2)。

The Full Stack of HTTP Requests for the Flight-Booking Operation
图 2 航班订票操作的 HTTP 请求的完全堆栈

SignalR 操作内

第一次请求从客户端页面中,在调用方法开始时触发 这标识到 SignalR 后端的客户端。 应当指出的是第一次请求是特别谈判请求。 它将永远无论连接谈判的最终运输的 AJAX。 任何 SignalR Web 页包含类似以下加载页面时运行的代码:

$(function () {
  var bookingHub = $.connection.bookingHub;
  bookingHub.start();
}

这种方式,页面声明其打开的连接,调用的服务器端 bookingHub 对象服务的意向。 请注意它不会按照集线器服务器端对象的公共接口的客户端对象创建的魔法的 SignalR。 JavaScript 对象的名称匹配的服务器对象的名称。 但是,您可以使用 HubName 属性修改客户端上使用的名称:

[HubName("booking")]
public class BookingHub : Hub
{
  ...
}

启动请求返回客户端会通过连同任何连续的请求的客户端 ID。

{"Url":"/signalr","connectionId":"2a119962-edf7-4a97-954b-e74f2f1d27a9"}

下一步,客户端库置于另一个连接请求。 这是"连接"的要求,这将导致 OnConnect 所引发的事件的服务器上的连接。 图 3 显示几个连接请求。

Reiterating Connection Requests
图 3 重申连接请求

第一次两分钟的时间 ; 第二个是仍然挂起。 这是本质的长轮询 — 客户端与服务器在不断开放的通道。 服务器超时请求两分钟后如果不执行任何操作,需要将数据发送到客户端的服务器上。 在航班订票应用程序用户界面中,有一个按钮,用户可以单击开始预订航班。 在用户单击该按钮时将执行下面的代码:

bookingHub.bookFlight("fco", "jfk");

如果您从上月的列创建示例应用程序,您应该有链接此代码的页面按钮的 click 处理程序。

BookingHub 对象所属的脚本,SignalR 下载通过 signalr/集线器的 URL,如图所示,在图 3。 bookingHub 是一个隐藏实施长轮询模式的复杂性的平原的代理对象。 单击按钮会触发新的请求到服务器的客户端 ID 嵌入的地方。 当服务器接收从挂起的调用的客户端的调用时,它结束挂起的调用,并开始处理新请求,如图所示,在图 4

A Multistep Operation Is Taking Place
图 4 多步操作是正在发生

图 4 显示挂起的请求 (signalr/发送)、 两个完成的请求和其他挂起的请求。 Signalr/发送请求是预订的航班,其源代码所示的宏操作的原始调用图 1

中的代码图 1 客户端调用以通知的任何进展,它的各个阶段,如下所示:

Clients.displayMessage(...);

在 signalr/发送的请求被放置的同时,另一个请求启动等待通知。 此请求等待,直到有一些数据发回。 向客户端在服务器代码中的任何调用完成的通知的请求,并立即触发另一个从客户端,所以在序列图 4 ,已完成两个步骤,并由客户端收到了两个进度消息的手段。 服务器进程则忙着试图完成的第三步。 中的代码年底图 1,所有请求中的 图 4 完成了,情况将会返回到一个类似于所示图 2

超越长轮询

如果你比较长的行为轮询在 SignalR 实施步骤如 AJAX 投票,关于我的文章你应该认识到的通用模式 — — 进度指示器模式。 AJAX 投票站和长时间轮询是两个不同的实现相同的图案。 哪一个是更有效,这取决于 Web 服务器的配置和应用程序的要求。 它是你的电话。 在任何情况下,如果您选择长轮询,则需要 SignalR 或类似的库。 如果您要构建您自己的框架,我建议你选择众多,但快速调用的越少,但长长的调用与 AJAX 投票的投票站。

建立有效的长轮询框架可能很棘手。 与 AJAX 投票可能你不连续的连通性,但你没有风险降低服务器的速度。 考虑到这一点,我可能不会绕过并更新我照顾任何实时 Web 服务器 SignalR。 但是,SignalR 释放后,我不明白什么理由不将其用于新的应用程序。

最后,值得一提的 SignalR 现在支持其他更高级的传输,除了长轮询。 在最新的源中,您还会发现 Windows 8 的服务器 ; 上 WebSockets 的支持 服务器发送事件对 Chrome、 火狐、 歌剧和 Safari ; 和永远框架对 Ie 浏览器。 库列表的开头开始,并使保持下降回直到找到支持的传输。 所以,最后,长时间轮询将实际上很少使用在大多数情况下。

Dino Esposito   是的作者"ASP 编程。网 4"(微软出版社,2011年) 和"ASP 编程。净 MVC 3"(微软出版社,2010年),并散布"微软。网络:规划为企业应用程序"(微软出版社,2008年)。 埃斯波西托在意大利是一个频繁的演讲者,在全球范围内的行业活动。 跟随他在 Twitter 上 Twitter.com/despos

多亏了以下的技术专家审查这篇文章:Damian Edwards