Carambolas是一個不斷發展的通用支持庫,由多個.NET標準2.0組件組成。尤其,它具有定制的多通道可靠的UDP協議實現,用於低延遲/低帶寬 - 延遲產品網絡應用程序,具有軟實時約束。
第一個版本是具有功能齊全的網絡模塊的最小核心。該存儲庫是圍繞單個解決方案構建的,因為我計劃將來通過添加新模塊來擴展。
測試覆蓋範圍仍然很小,因此如果不對源代碼進行仔細檢查,則不應暗示任何正確性。這是一個最早階段的持續項目。
二進製文件即將在存檔部分或Nuget軟件包的形式中提供。
本地主機由carambolas.net.host的實例表示。它必須用於連接到遠程主機或接受傳入的連接。
每個遠程主機都由Carambolas.net.peer的實例表示。
連接,斷開連接和數據等事件是通過主機對象接收的,而PEER對象可用於發送數據或主動斷開連接。
在這一點上,連接,斷開,發送和接收操作是無障礙的;開放和關閉正在阻止(出於明顯的原因)。
請注意,同一主機對象可用於主動請求連接並接受傳入的連接,從而使其在P2P拓撲中可用。客戶/服務器角色不會僅通過如何配置主機來執行和出現。主機甚至可以同時向多個遠程主機發送連接請求。
示例:
主機對象實例化以連接到遠程對等。內部循環負責確保事件不會加入下一次迭代。
using ( var host = new Host ( "MyHost" )
{
host . Open ( IPEndPoint . Any , new Host . Settings ( 0 ) ) ;
host . Connect ( new IPEndPoint ( IPAddress . Loopback , 1313 ) , out Peer peer ) ;
.. .
while ( true )
{
while ( host . TryGetEvent ( out Event e ) )
{
if ( e . EventType == EventType . Data )
Console . WriteLine ( $ "DATA: { e . Peer } { e . Data } " ) ;
else if ( e . EventType == EventType . Connection )
Console . WriteLine ( $ "CONNECTED: { e . Peer } " ) ;
else if ( e . EventType == EventType . Disconnection )
{
Console . WriteLine ( $ "DISCONNECTED: { e . Peer } { e . Reason } " ) ;
return ;
}
}
Thread . Sleep ( 33 ) ;
}
}主機對象實例化,最多等待10個傳入連接。內部循環負責確保事件不會加入下一次迭代。
using ( var host = new Host ( "MyHost" )
{
host . Open ( new IPEndPoint ( IPAddress . Loopback , 1313 ) , new Host . Settings ( 10 ) ) ;
.. .
while ( true )
{
while ( host . TryGetEvent ( out Event e ) )
{
if ( e . EventType == EventType . Data )
Console . WriteLine ( $ "DATA: { e . Peer } { e . Data } " ) ;
else if ( e . EventType == EventType . Connection )
Console . WriteLine ( $ "CONNECTED: { e . Peer } " ) ;
else if ( e . EventType == EventType . Disconnection )
{
Console . WriteLine ( $ "DISCONNECTED: { e . Peer } { e . Reason } " ) ;
return ;
}
}
Thread . Sleep ( 33 ) ;
}
} 該項目可以追溯到2015年,當時我來加拿大學習多倫多電影學校的視頻遊戲設計和開發。最初的動機是創建可以在多個Unity3D項目中重複使用的配件類的彙編。一段時間後,我開始研究前景多人遊戲的網絡解決方案,重點轉向設計可重複使用的網絡模塊。最初,我將問題作為一個簡單的問題,即集成了我當時可以找到的任何其他合適的第三方庫。不久之後,我開始遇到各種各樣的問題,從破裂的假設到隱藏的實施權衡。發現膨脹(幾乎具有誤導性)功能列表,設計不兼容或純粹的破壞實現並不少見。特別是,最困擾我的是,解決方案的許多方面似乎是隨機任意的,幾乎沒有解釋為什麼這種方法是首選的或施加的一定限制。我會花幾個小時檢查一個項目的來源記錄,以弄清楚為什麼只有後來才意識到代碼的另一部分是直接矛盾的。
所有這些都促使我從事更多工作,最終我決定自己建立一個可以實現和驗證的合理功能列表的輕量級網絡庫。沒有匆忙,沒有截止日期。只是一個真正的嘗試,試圖實施我可以設計的最佳技術解決方案。
同時,我畢業了,回到了一份全職工作,不得不將這個項目擱置一旁。一年前,在找到了一些舊的筆記後,我恢復了原型檔案,並決定將我收集的所有信息匯總在一起,以便不僅其他人可以嘗試它,而且還了解它的工作方式和原因。
可以在任何平台中使用支持C#7.3或更高版本的編譯器構建託管組件。測試和附件應用需要NetCore 2.2。
可以使用GCC或Visual Studio的CMAKE構建本地庫。
支持的OS版本:
對於任何其他平台,或在沒有必需的本地庫的情況下,後備代碼一般而言,雖然效率可能較低,必須具有完全功能性和透明性。
所有C#項目和構建腳本均配置為將中間文件和二進製文件存儲在位於項目根部的構建文件夾下,因此可以輕鬆地檢查,驗證和清潔構建。
該代碼使用dllimport綁定本機庫。 Dllimport可能始終使用Windows庫名稱,並根據需要自動添加其他平台的前綴/後綴。例如,carambolas.net.native.dll,Windows上的Net Native Library的名稱,變成Linux上的Libcarambolas.net.native.dll。構建腳本已經以專有名稱創建庫。
為了方便起見,包括視覺工作室解決方案,因此Windows不需要其他構建步驟。僅確保選擇與主機操作系統相對應的平台(X86或X64)。構建測試應用程序和單位測試是必需的。所有.NET組件都是為AnyCPU構建的,無論選擇的解決方案平台如何,但是Visual Studio必須知道要構建哪些本機庫進行測試,因為預計它們會與相關的組件並排部署。
使用nugetpack.bat來編譯本機庫和便攜式組件,並在單個操作中創建Nuget軟件包。
使用build.bat在不使用Visual Studio的情況下構建所有項目供發布。
Mac的Visual Studio尚未進行測試,也不支持,因此不要指望它可以正常工作。
確保具有CMAKE(> = 2.8)和GCC,以便能夠編譯本機庫。需要DOTNET CORE SDK 2.1來編譯組件並生成Nuget軟件包。
使用nugetpack.sh來編譯本機庫和便攜式組件,並在單個操作中創建Nuget軟件包。
使用build.sh在不使用Visual Studio的情況下構建所有項目供發布。
確保安裝了CMAKE(> = 2.8),Build-Endenteal和GCC-Multilib,以便能夠為X86和X64編譯本機庫。
在Ubuntu Run:$ sudo apt-get install build-extent build-extential gcc-multilib g ++ -multilib cmake
需要編譯組件並生成Nuget軟件包需要Dotnet Core SDK 2.1。
在Ubuntu Run:
$ wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
$ sudo dpkg -i packages-microsoft-prod.deb
$ sudo apt-get update;
sudo apt-get install -y apt-transport-https &&
sudo apt-get update &&
sudo apt-get install -y dotnet-sdk-2.1
使用nugetpack.sh來編譯本機庫和便攜式組件,並在單個操作中創建Nuget軟件包。
使用build.sh在不使用Visual Studio的情況下構建所有項目供發布。
使用Xunit項目圍繞關鍵功能實施了最小的單元測試集。
Carambolas.net.tests.host是一種簡單的控制台應用程序,用於手動驗證基本網絡功能。當與Wireshark和笨拙的一側時,這特別有用
Carambolas.net.tests.Integration是Carambolas.net的一組集成測試,也與Xunit實施。測試依次運行,每個測試啟動兩個單獨的線程(服務器和客戶端),這些線程在特定的時間內通過環回接口進行通信。回環代表了一個理想的網絡,其中往返時間最少,數據包永遠不會過時,除非有淡淡的溢出,否則不會丟失。這些特徵對於驗證正常的執行路徑很有用。
Wireshark是一種寶貴的調試工具,可用於監視網絡活動和檢查數據包。此外,Wireshark還支持一類稱為解剖器的特殊類別的插件,該插件可用於分析自定義協議。
該項目包括Carambolas的基本Wireshark解剖器。為了使用它,請確保已經安裝了Wireshark。
Clumsy是一個網絡數據包捕獲程序,它以用戶模式運行,能夠攔截數據包實時模擬退化的網絡條件。
在config.txt文件中添加以下內容的預設過濾器行,以影響由環回接口連接的主機在集成測試中使用的同一端口上(1313):
carambolas: udp and outbound and loopback and (udp.DstPort == 1313 or udp.SrcPort == 1313)
請注意,在使用Loopback接口使用笨拙時,有一些警告。從笨拙的用戶手冊中:
- 環回入口數據包無法捕獲或重新註射。當您考慮一下時,當您將數據包從計算機發送到本身時,很難說它是一個入站或出站數據包。實際上,底層Windows過濾平台似乎將所有環回包數據包分類為出站。要記住的事情是,當您在環回包數據包上處理時,您的過濾器中不能有“入站”。重要的是要知道您的計算機可能具有127.0.0.1以外的IP,就像路由器分配的Intranet IP一樣。這些也被視為回環數據包。
- 回環包被捕獲兩次。由於我們沒有入站環回數據包,因此所有回環數據包都被視為出站。因此,笨拙的過程將兩次處理:第一次是發送時,第二次接收時。一個簡單的例子是,當過濾器簡單地“出站”並應用500ms時。當您ping localhost時,它將是1000ms的滯後。您可以通過指定目標端口以及類似的內容來解決它。但是,在設置參數時,請記住這一點會更容易。
- 入站數據包捕獲一直無法運行。如前所述,環回入口數據包無法重新註射。問題是,即使目標IP不在您的計算機中,有時某些數據包也可能被歸類為入站數據包。這僅影響非環回包。如果您僅在Local主持那里工作,那就可以了。未來發布的目的是診斷導致此問題的原因並提供解決方案。
- 無法基於過程系統寬網絡捕獲的過濾被列為一項功能。但這確實是因為沒有簡單的方法可以提供強大的解決方案。
我總是以錯誤報告的形式,錯誤修復(甚至更好!)或改進的測試覆蓋範圍供應。
歡迎功能請求,但可以將其保存在積壓中,具體取決於它們的廣泛,可行或可取的程度。如果功能請求太複雜,則可能取決於贊助,因為我的資源(時間和金錢)有限。
如果您想支持這個項目,我可能有興趣收到您的來信,請伸出援手!
在葡萄牙語中,卡蘭博拉斯是卡蘭博拉(= starfruit)的複數形式。該術語在巴西的某些地區也被通俗地使用,以表達驚訝或不耐煩。
在Carambolas之前,我至少做了六次嘗試在一個可用項目中組織我的想法。使用Carambolas,我決定構建一系列原型,以了解設計問題並測試不同的方法。每個原型都有一個由字母形成的代碼名稱,從A1開始的數字。最初在此存儲庫中導入的源代碼是第9個原型的第75次迭代,因此A9。
本地圖書館主要出於績效原因提供,因此它們是完全可選的。嘗試為每個可能的平台提供一個本機實現是不合理的(考慮所有台式機,移動,控制台,嵌入式...),並且僅依靠本機庫將使目標平台僅將目標平台減少到僅少數台式機(Windows,Linux和MacOS)。因此,作為經驗法則,託管代碼中必須始終為本機庫實現的任何功能實現後退實現。
由於本機庫是可選的,因此該程序無法判斷是否應該存在一個丟失的文件,因此為什麼沒有出現錯誤或記錄的丟失本機庫的錯誤。根據定義,缺失的本機庫絕不是錯誤。
通常,你不能。至少您不應該從API的角度來看。對於用戶(或應用程序編程器),在這種情況下,在這種情況下,carambolas採用了什麼基本實施策略。但是,此信息可能與部署有關,因此,每當創建一個具有自動後備的Interop對象時,代碼都會產生指示性日誌信息。例如,Carambolas.net.socket將產生類似於“使用carambolas.net.sockets.native.socket”的日誌信息,當時找到了用於基礎插座實現的本地庫。這樣,如果您要考慮到本機庫,則可以確定它們是否實際使用。
這意味著您正在部署一個本地庫,該庫是損壞或為錯誤的CPU體系結構編譯的本地庫。
本地庫必須與相應的互動組件並排進行,儘管可以為任何CPU架構編譯一次組件,但本機庫不能。它們必須匹配運行操作系統的CPU體系結構,否則將它們視為損壞的文件,並且.NET拋出系統。 BADIMAGEFORMATEXCEPTION。請注意,這與試圖加載未找到的庫,而不是錯誤。
帶寬 - 延遲產品(BDP)是網絡鏈路的傳輸容量(以每秒位數為單位)及其往返延遲時間(以秒為單位)的產物。它代表網絡可以保留的最大數據,然後才能到達任何確認。
BDP可用於根據網絡對網絡進行分類,是高於或低於特定閾值。 BDP較大的網絡稱為長脂肪網絡(LFN)。 LFN可以是具有非常大的平均往返時間(如衛星鏈路中的帶寬)的網絡,也可以是一個寬的(高帶寬)網絡,它顯示出相當小的往返時間(如Gigabit以太網鏈路中)。
檢查Wikipedia以獲取有關它的更多信息。
carammbolas.net.socket對像是本機套接字實現或依賴System.net.sockets.socket的後備實現的立面。它有助於將主機和同伴對象的複雜性解矛和降低。有關更多信息,請參閱DOC/README-CARAMBOLAS.NET。
system.net.ipaddress和system.net.ipendpoint是可變的對象,在.NET CORE和.NET框架的所有當前構建中促進許多不必要的分配。 carambolas.net.ipaddress和carambolas.net.ipendpoint是有助於降低GC壓力的不可變值類型。有關更多信息,請參閱DOC/README-CARAMBOLAS.NET。
與Chacha20和Poly1305的AEAD在開箱即用。可以通過向主機提供Carambolas.net.icipher和carambolas.net.icipherfactarfactractory接口來實現自定義策略。唯一的要求是:
用戶應用程序可以在發送之前自由壓縮數據,但是目前沒有提供自動壓縮/解壓縮的單個消息或完整數據包的機制。
所有與用戶應用程序一起部署的源代碼和所有生產的二進製文件均根據MIT許可獲得許可。
Carambolas.commandlinearguments基於Griffonrl的一篇文章,其源代碼在MIT許可下發布,並在Jake Ginnivan的另一篇文章中提供了其他想法,該文章擴展了原始資料。
Carambolas.security.criptography.crc32c以武力為基於MIT許可證的CRC32.NET。
carambolas.security.criptography.nacl在MIT許可下由David de Smet的NACl.Core擴展。
在LUA中為Wireshark編寫的協議解剖器可根據GPLV3許可證獲得。它僅被用作Wireshark的輸入文件,以擴展其功能,並允許它顯示有關Carambolas Network Network協議格式化的UDP數據包的更多信息。因此,它是完全分開的,並且不相互作用,取決於或以任何方式貢獻任何源文件,彙編或本機庫。