切削刃

長輪詢與 SignalR

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)。


圖 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 顯示幾個連接請求。


圖 3 重申連接請求

第一次兩分鐘的時間 ; 第二個是仍然掛起。這是本質的長輪詢 — — 用戶端與伺服器在不斷開放的通道。伺服器超時請求兩分鐘後如果不執行任何操作,需要將資料發送到用戶端的伺服器上。在航班訂票應用程式使用者介面中,有一個按鈕,使用者可以按一下開始預訂航班。在使用者按一下該按鈕時將執行下麵的代碼:

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

如果您從上月的列創建示例應用程式,您應該有連結此代碼的頁面按鈕的 click 處理常式。

BookingHub 物件所屬的腳本,SignalR 下載通過 signalr/集線器的 URL,如圖所示,在圖 3。bookingHub 是一個隱藏實施長輪詢模式的複雜性的平原的代理物件。按一下按鈕會觸發新的請求到伺服器的用戶端 ID 嵌入的地方。當伺服器接收從掛起的調用的用戶端的調用時,它結束掛起的調用,並開始處理新請求,如圖所示,在圖 4


圖 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