.NET 的 WebSocket 開發包比較

類別: IT

編者按

本文出現在第三方產品評論部分中。在這一部分的文章只提供給會員,不允許工具供應商用來以任何方式和形式來促銷或宣傳產品。請會員報告任何垃圾資訊或廣告。

Web專案常常需要將資料儘可能快地推送給客戶,必要時無需等待客戶端請求。對於與使用者之間進行實時通訊的網站,例如線上交流或文件協作工具,或者在長期執行的計算/執行任務的伺服器上更新系統狀態,等等這些時候,採用雙向溝通機制是理想的。

以前,這類問題一般使用下面的解決方案:

  • 使用 Flash 中的 Socket 連線(http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/Socket.html)

  • Ajax 長輪詢(https://gist.github.com/jasdeepkhalsa/4353139)

  • 伺服器傳送事件... (http://en.wikipedia.org/wiki/Server-sent_events)

  • ...或者就用 IE 中經典的 Frame 技術Smile (http://cometdaily.com/2007/11/05/the-forever-frame-technique/)

但現在我們有了更好的選擇:WebSocket。它的標準在2011年釋出,在現代瀏覽器上已實施了一段時間。它更好的原因是使用更安全和更成熟的協議,帶來了改進和升級。

略注:

這份比較是幾個月前做的,可能不夠及時,但如果有人要找好的WebSocket庫,我認為這對他仍然是有用的。

本比較只針對以 NuGet 包形式釋出的庫, SuperWebSocket 雖然使用 NuGet 的 repository,但需要從網頁中下載。

也許等我抽出空來,我會使用新的庫或已測試的庫的新版本進行比較然後更新這篇文章。

Fleck

https://github.com/statianzo/Fleck

我發現這個庫真的是簡單易用,對於庫、文件、例子等都是,只要新增庫,複製幾行例子裡的程式碼,然後執行——就這麼簡單。

但是簡單是有代價的:其功能並不強大,且可配置的地方太少。

private static void Main(string[] args){     var server = new WebSocketServer("ws://localhost:8181");     server.Start(socket =>     {          socket.OnOpen = () => OnOpen(socket);          socket.OnClose = () => OnClose(socket);          socket.OnMessage = m => OnMessage(socket, m);     });}

對於簡單快速的專案我會用它,如果你不需要用WebSocket傳送太複雜的資料結構、命令一樣的訊息、或在客戶端無WebSocket支援時的備選方式,這就是你要的了。

優點:

  • 簡單

  • 無依賴項

缺點:

  • 可配置項少

  • 客戶端瀏覽器不支援WebSocket時就沒戲了

SignalR

http://www.asp.net/signalr

微軟出品是我認為這個庫最大的優點了。它已經和現有的ASP.NET框架做了整合,對伺服器端和客戶端程式碼都做了很好的抽象類, 這意味著你不需要太深入瞭解協議的東西。然後它還可以很聰明地在客戶端瀏覽器不支援WebSocket時自動使用別的通訊機制。它還可以完成一些叫遠端過程呼叫(RPC)的東西,從伺服器到客戶端。 

它能廣播訊息到所有客戶端,也能單獨發給指定使用者。對大量併發連線的處理也很優秀。還有——它是開源的!

聽起來很棒是不?但是...它需要IIS8或者說Windows Server 2012(Windows8也行,不過相信你不會在win8上面跑大專案的)。對我來說,這就是“微軟新一代值得買的作業系統”的超酷特性。如果開發企業專案的話是不錯的,但對小專案來說,為了這個開源的庫買作業系統——太貴了

當然這些環境是WebSocket必須要求的. 這篇文章就是講WebSocket通訊的,所以我把這個算成大缺點。

public class MyHub1 : Hub{    public void Send(string name, string message)    {        // Call the broadcastMessage method to update clients.        Clients.All.broadcastMessage(name, message);    }}

$(function () {    var chat = $.connection.myHub1;    chat.client.broadcastMessage = function (name, message) {        //...    };    $.connection.hub.start().done(function () {        $('#sendmessage').click(function () {            chat.server.send('message');        });    });});

優點:

  • 非常好的抽象

  • 與IIS和ASP.NET緊密整合

  • 很多候選方式

  • 開源

  • 微軟官方庫

  • 可擴充套件性好

缺點:

  • 需要IIS8…

  • … 也就是Windows Server 2012太貴了

AlchemyWebSocket

http://alchemywebsockets.net/

當我想到websocket庫時,這個讓人不可思議。沒錯這是真的。它可以排在Fleck後面,它非常容易使用,容易安裝(Nuget包可用),文件中含有很好的例子。

它包含服務端和客戶端兩部分,同時也具有可伸縮性

static void Main(string[] args){    // 建立一個新的server - 接受埠和ip範圍,    // 設定方法    var aServer = new WebSocketServer(81, IPAddress.Any)    {        OnReceive = OnReceive,        OnSend = OnSend,        OnConnect = OnConnect,        OnConnected = OnConnected,        OnDisconnect = OnDisconnect,        TimeOut = new TimeSpan(0, 5, 0)    };    aServer.Start();    string consoleReadLine;    do    {        consoleReadLine = Console.ReadLine();        sockets.ForEach(s => s.Send(consoleReadLine));    } while (consoleReadLine != "exit");}

但是它有一些彆扭,我不能避開。例如那裡沒有簡單的事件方法"OnReceive",僅僅只有string,事實上訊息在客戶端被髮送了。你必須你自己完成。是的,你必須呼叫,而且只能呼叫 .ToString()來得到真實的訊息,但使用庫的目的是為了不要強迫自己實現通訊協議。

private static void OnReceive(UserContext context){    Console.WriteLine("Client " + context.ClientAddress.ToString() + " sended: " + context.DataFrame.ToString());}

WebSocket伺服器初始化方法首先接收埠然後是IP設定。我一直認為,地址的表達應該是先IP然後是埠,而且只有當有必要指明埠的時候。還有超時設定:為什麼必須有超時呢?我可以理解這有時可能是有用的,但它作為一個特性不應作為主要設定之一。當然,這只是一些細節問題。

對我來說這迫使你一開始就得通過這個庫用另一層程式碼把它抽象出來。

總之你可以試試,和Fleck比較一下效能,然後決定哪個更適合你的簡單專案。

優勢:

  • 簡單

  • 無依賴性

  • 文件完備

缺點:

  • 有點笨拙,比Fleck結構更復雜

  • 沒有 fallback

XSockets

http://xsockets.net/

這個庫看上去很有前途。我嘗試過它,並且還花了很多時間,用它工作超過其它的庫(甚至用來執行測試工作等等)。但是很不幸我沒有運氣,任何我考慮到的錯誤在這個庫中都是錯誤的,與程式碼不一致的糟糕文件。難道是因為程式碼或者文件過期了?它不容易安裝和執行,事實上這個庫的使用樣例我很難組建和執行。Xsocket更多向我們展示了MVC框架的樣子。我嘗試把它執行在ASP.NET專案裡面,MVC和WinService,遺憾的是沒有一個能夠工作。

我真的很想用這個庫,但最後我放棄了以便支援更好的庫(閱讀其他)。認真地說為什麼使用這個庫是困難的,甚至一個簡單的專案。你可以預測更多的問題當把它使用在專案裡,我強烈建議避開這個專案。

public static class XSocketsBootstrap{    private static IXBaseServerContainer wss;    public static void Start()    {                    wss = XSockets.Plugin.Framework.Composable.GetExport();        wss.StartServers();    }}

<p>Advantages:</p><ul><li>Seems powerful</li><li>Should have good JavaScript integration</li></ul><p>Disadvantages:</p><ul><li>Complicated and hard</li><li>Complicated to configure and run inside of WebForms, MVC and WinService</li><li>Differences between code and documentation</li><li>Outdated documentation and examples</li></ul></li><li><h2>Microsoft.WebSocket</h2><p><a href="http://msdn.microsoft.com/en-us/hh969243.aspx">http://msdn.microsoft.com/en-us/hh969243.aspx</a></p><p>Another library from Microsoft. And it requires IIS 8 too, so I did not have means to test it. Examples are really low level, so it force you to deal with buffers and streams instead of strings. In some cases this can be good, but mostly there is no point. If you have IIS 8 on server why bother with this library if you can use SignalR, which will take care most of the stuff for you.</p><p>I think this is more of proof-of-concept then usable library.</p><pre>int count = receiveResult.Count;while (receiveResult.EndOfMessage == false){    if (count >= maxMessageSize)    {        string closeMessage = string.Format("Maximum message size: {0} bytes.", maxMessageSize);        await socket.CloseAsync(WebSocketCloseStatus.MessageTooBig, closeMessage, CancellationToken.None);        return;    } receiveResult = await socket.ReceiveAsync(new ArraySegment(receiveBuffer, count, maxMessageSize - count), CancellationToken.None);    count += receiveResult.Count;} var receivedString = Encoding.UTF8.GetString(receiveBuffer, 0, count);var echoString = "You said " + receivedString;ArraySegment outputBuffer = new ArraySegment(Encoding.UTF8.GetBytes(echoString));await socket.SendAsync(outputBuffer, WebSocketMessageType.Text, true, CancellationToken.None);

SuperWebsocket

http://superwebsocket.codeplex.com/

最後但並不是最不重要的是SuperWebsocket。我對這個有一點懷疑(如果我沒記錯的話,這僅僅是一個我通過NuGet網站發現的包,但又不是一個可用的包)。它似乎有一點複雜,但實際上它是非常簡單的。有文獻支援的例子幫助你一步步的從最簡單的WebSocket伺服器,到有命令請求,JSON,多伺服器例項,.config檔案配置或者更多的複雜Websocket伺服器。

這個庫也許沒有包含所有其他庫有的那些很酷的特性,但是這沒關係,因為它是高度可配置的,你可以很容易的讓它實現你想要的。它可以作為控制檯應用程式或者windows服務執行於ASP.NET中。文獻上則建議以系統服務的形式來執行伺服器。從我的經驗來看,建議不要在一個web應用程式裡面執行它因為這種解決方案很慢(非常糟糕的表現,比控制檯應用程式大約慢50倍)。從另一方面,獨立的伺服器應用程式,需要執行.exe結尾的檔案,這個檔案並不是庫的一部分,但是是SuperSocket專案的一部分(SuperWebSocket就是基於這個專案的)。這使得你需要一點技巧在除錯會話中開啟伺服器,或者完全啟用除錯。當你作為應用程式執行伺服器的時候,雖然這不是解決方案的一部分,也需要確保伺服器採用來自其他專案的最新版的元件。

作為回報,你得到了關於靈活的WebSocket的眾所周知的解決方案。

它仍然是開源的所以你可以根據需要改變它。

從另一方面,你可能把這個伺服器缺乏JavaScript客戶端看做是它的缺點(但是它有C#客戶端)。這個伺服器也有第三方的依賴關係。

在使用這個庫工作了幾個月之後我沒發現什麼主要的問題。

缺點和優點:

  • 無備用通訊

  • 依賴

  • 優雅的特性和高度可配置性

  • 很棒的例子

  • 例子的都有推薦設定的文件

  • 可以作為windows服務和ASP.NET模組和控制檯應用程式執行

  • 好的效能表現

總結

對於複雜的解決方案/專案我建議用SuperWebSocket,因為它是一個穩定而且高度可配置的庫。對於簡單和需要快速開發的專案我會選擇Fleck,但是如果有辦法使用最新的windows伺服器來作為測試和生產機器的話,我會放棄使用這兩個而選擇SignalR。

.NET 的 WebSocket 開發包比較原文請看這裡