Carambolas ist eine sich ständig weiterentwickelnde Bibliothek für allgemeine Support -Bibliothek, die aus mehreren .NET Standard 2.0 -Baugruppen besteht. Insbesondere, Es verfügt über eine benutzerdefinierte Multi-Channel-zuverlässige UDP-Protokoll-Implementierung für Produktnetzwerkanwendungen mit geringer Latenz-/Niedrigbandbreite mit sanften Echtzeitbeschränkungen .
Die erste Version ist ein minimaler Kern mit einem voll funktionsfähigen Netzwerkmodul. Dieses Repository ist um eine einzelne Lösung strukturiert, da ich vorhabe, in Zukunft neue Module hinzuzufügen.
Die Testabdeckung ist nach wie vor minimal, so dass ohne eine genaue Prüfung des Quellcode keine Korrektheit impliziert werden sollte. Dies ist ein fortlaufendes Projekt in den frühesten Stadien.
Binärdateien sind bald im Archivabschnitt oder in Form von Nuget -Paketen erhältlich.
Der lokale Gastgeber wird durch eine Instanz von carambolas.net.host vertreten. Es muss verwendet werden, um eine Verbindung zu einem Remote -Host herzustellen oder eingehende Verbindungen zu akzeptieren.
Jeder Remote -Host wird durch eine Instanz von carambolas.net.peer dargestellt.
Ereignisse wie Verbindung, Trennung und Daten werden über das Host -Objekt empfangen, während Peer -Objekte zum Senden von Daten oder zur aktiven Trennung verwendet werden.
An diesem Punkt verbinden, trennen, senden und empfangen sind nicht blockierende Operationen. Offen und nah blockieren (aus offensichtlichen Gründen).
Beachten Sie, dass dasselbe Host -Objekt verwendet werden kann, um die Verbindungen aktiv anzufordern und eingehende Verbindungen gleich zu akzeptieren, was sie in P2P -Topologien verwendbar macht. Client/Server -Rollen werden nicht durchgesetzt und entstehen einfach daran, wie ein Host konfiguriert ist. Ein Host senden möglicherweise sogar Verbindungsanfragen an mehrere Remote -Hosts gleichzeitig.
Beispiele :
Host -Objekt instanziiert, um eine Verbindung zu einem Remote -Peer herzustellen. Die innere Schleife ist verantwortlich, um sicherzustellen, dass Ereignisse nicht auf die nächste Iteration akkumulieren.
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 ) ;
}
}Host -Objekt instanziiert, um auf bis zu 10 eingehende Verbindungen zu warten. Die innere Schleife ist verantwortlich, um sicherzustellen, dass Ereignisse nicht auf die nächste Iteration akkumulieren.
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 ) ;
}
} Dieses Projekt stammt aus dem Jahr 2015, als ich nach Kanada kam, um das Design und die Entwicklung von Videospielen an der Toronto Film School zu studieren. Die ursprüngliche Motivation bestand darin, eine Zusammenstellung von Zubehörklassen zu erstellen, die in mehreren Unity3D-Projekten wiederverwendet werden konnten. Nach einer Weile begann ich, Netzwerkelösungen für ein Multiplayer -Spiel für das Prospect zu recherchieren, und der Fokus verlagerte sich auf die Gestaltung eines wiederverwendbaren Netzwerkmoduls. Anfangs habe ich mich dem Problem an die Integration von Unet oder einer anderen geeigneten Bibliothek von Drittanbietern angenommen, die ich zu diesem Zeitpunkt finden konnte. Kurz darauf stieß ich auf alle möglichen Probleme, von gebrochenen Annahmen bis hin zu den Kompromisse für die Implementierung. Es war nicht ungewöhnlich, aufgeblasene (fast irreführende) Funktionslisten, Design -Inkompatibilitäten oder einfache kaputte Implementierungen zu finden. Insbesondere störte mich am meisten, dass viele Aspekte der Lösungen zufällig willkürlich schienen, mit wenig bis gar keine Erklärung dafür, warum dieser Ansatz bevorzugt oder eine bestimmte Grenze auferlegt wurde. Ich würde Stunden damit verbringen, die Quelle eines Projekts zu inspizieren, um sich Notizen zu ermitteln, um herauszufinden, warum etwas so war, wie es später erkennen konnte, dass ein weiterer Teil des Code in direktem Widerspruch war.
All dies hat mich in mehr Arbeit gebracht und schließlich beschloss ich, selbst eine leichte Netzwerkbibliothek mit einer angemessenen Funktionsliste zu erstellen, die ich implementieren und überprüfen konnte. Kein Ansturm, keine Fristen. Nur ein echter Versuch, die beste technische Lösung zu implementieren, die ich entwickeln konnte.
In der Zwischenzeit machte ich meinen Abschluss, ging zu einem Vollzeitjob zurück und musste dieses Projekt beiseite legen. Vor einem Jahr, nachdem ich einige alte Notizen gefunden hatte, stellte ich mein Prototyparchiv wieder her und beschloss, einen umfassenden Build mit all den Informationen zusammenzustellen, die ich gesammelt habe, damit nicht nur andere Menschen damit experimentieren, sondern auch verstehen, wie es funktioniert und warum.
Die verwalteten Baugruppen können in jeder Plattform mit einem Compiler integriert werden, der C# 7.3 oder höher unterstützt. Tests und Zubehöranwendungen erfordern NetCore 2.2.
Native Bibliotheken können mit CMake mit GCC oder Visual Studio erstellt werden.
Unterstützte Betriebssystemversionen:
Für jede andere Plattform oder in Ermangelung einer erforderlichen nativen Bibliothek besteht der Fallback -Code, dass zwar im Allgemeinen weniger effizient sein kann, voll funktionsfähig und transparent sein muss.
Alle C# -Projekte und Build -Skripte sind so konfiguriert, dass Zwischendateien und Binärdateien unter einem Build -Ordner, der sich an der Projektroste befindet, so problemlos überprüft und gereinigt werden können.
Der Code verwendet DLLImport, um native Bibliotheken zu binden. DLLImport kann immer Windows -Bibliotheksnamen verwenden und werden nach Bedarf automatisch die Präfixe/Suffixe anderer Plattformen hinzufügen. Beispielsweise wird Carambolas.net.Native.dll, der Name der nativen NET -Bibliothek unter Windows, libcarambolas.net.native.dll.so unter Linux und libcarambolas.net.Native.dll.dynlib auf macos. Erstellen Sie Skripte erstellen die Bibliotheken bereits unter den richtigen Namen.
Für Windows ist eine Visual Studio -Lösung für den Einfachheit halber enthalten. Stellen Sie nur sicher, dass Sie die Plattform auswählen, die Ihrem Host -Betriebssystem entspricht (entweder x86 oder x64). Dies ist erforderlich, um die Testanwendungen und für Unit -Tests zu erstellen. Alle .NET-Baugruppen sind für AnyCPU unabhängig von der ausgewählten Lösungsplattform erstellt. Visual Studio muss jedoch wissen, welche nativen Bibliotheken für Testen erstellt werden müssen, da sie erwartet werden, dass sie nebeneinander mit ihren zugehörigen Baugruppen eingesetzt werden.
Verwenden Sie Nugetpack.bat, um die native Bibliothek und tragbare Baugruppen zu kompilieren und Nuget -Pakete in einer einzigen Aktion zu erstellen.
Verwenden Sie Build.bat, um alle Projekte zur Veröffentlichung zu erstellen, ohne Visual Studio zu verwenden.
Visual Studio für Mac wurde nicht getestet und wird nicht unterstützt. Erwarten Sie also nicht, dass es funktioniert.
Stellen Sie sicher, dass CMake (> = 2,8) und GCC die native Bibliothek zusammenstellen können. Dotnet Core SDK 2.1 ist erforderlich, um die Baugruppen zu kompilieren und Nuget -Pakete zu generieren.
Verwenden Sie Nugetpack.sh, um die native Bibliothek und tragbare Baugruppen zu kompilieren und Nuget -Pakete in einer einzigen Aktion zu erstellen.
Verwenden Sie Build.sh, um alle Projekte zur Veröffentlichung zu erstellen, ohne Visual Studio zu verwenden.
Stellen Sie sicher, dass Sie CMake (> = 2,8), Build-Escial und GCC-Multilib installiert haben, um die native Bibliothek sowohl für x86 als auch für x64 kompilieren zu können.
Auf Ubuntu Run: $ sudo apt-Get Installieren Sie build-wesentliche GCC-Multilib G ++-Multilib Cmake
Dotnet Core SDK 2.1 ist erforderlich, um Baugruppen zu kompilieren und Nuget -Pakete zu generieren.
Auf 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
Verwenden Sie Nugetpack.sh, um die native Bibliothek und tragbare Baugruppen zu kompilieren und Nuget -Pakete in einer einzigen Aktion zu erstellen.
Verwenden Sie Build.sh, um alle Projekte zur Veröffentlichung zu erstellen, ohne Visual Studio zu verwenden.
Ein minimaler Satz von Unit -Tests wird mithilfe von Xunit -Projekten um wichtige Funktionen implementiert.
Carambolas.net.tests.host ist eine einfache Konsolenanwendung, mit der grundlegende Netzwerkfunktionen manuell überprüft werden. Es ist besonders nützlich, wenn es sich mit Wireshark und ungeschickt befindet
Carambolas.net.tests.integration ist eine Reihe von Integrationstests für carambolas.net, die ebenfalls mit Xunit implementiert ist. Die Tests führen nacheinander aus, wobei jeweils zwei separate Threads (ein Server und ein Client) startet, die über die Loopback -Schnittstelle für eine bestimmte Zeitspanne kommunizieren. Der Loopback stellt ein ideales Netzwerk dar, in dem die Hin- und Rückfahrt minimal ist. Pakete kommen nie außerhalb der Reihenfolge an und gehen niemals verloren, es sei denn, es gibt einen Bufffer-Überlauf. Diese Eigenschaften sind nützlich, um normale Ausführungspfade zu validieren.
Wireshark ist ein unschätzbares Debugging -Tool, mit dem die Netzwerkaktivität überwacht und Pakete inspiziert werden kann. Darüber hinaus unterstützt Wireshark eine spezielle Klasse von Plugins, die als Dissektoren bezeichnet werden und zur Analyse benutzerdefinierter Protokolle verwendet werden können.
Dieses Projekt umfasst einen grundlegenden Wireshark -Dissktor für Carambolas. Um es zu verwenden, stellen Sie sicher, dass Wireshark bereits installiert ist.
Clumsy ist ein Netzwerkpaket-Capture-Programm, das im Benutzermodus ausgeführt wird und in der Lage ist, Pakete abzufangen, um die abgebauten Netzwerkbedingungen in Echtzeit zu simulieren.
Fügen Sie eine voreingestellte Filterzeile wie die folgende in der Datei config.txt hinzu, um Hosts zu beeinflussen, die von der Loopback-Schnittstelle auf demselben Port in Integrationstests (1313) verwendet werden:
carambolas: udp and outbound and loopback and (udp.DstPort == 1313 or udp.SrcPort == 1313)
Beachten Sie, dass es einige Vorbehalte gibt, wenn die Loopback -Schnittstelle ungeschickt verwendet wird. Aus dem ungeschickten Benutzerhandbuch:
- Loopback -Inbound -Pakete können nicht erfasst oder zurückgegeben werden. Wenn Sie darüber nachdenken, ist es wirklich schwierig zu sagen, dass es sich um ein eingehendes oder ein ausgehendes Paket handelt, wenn Sie Pakete vom Computer an sich selbst senden. Tatsächlich scheint die zugrunde liegende Windows -Filter -Plattform alle Loopback -Pakete als ausgehender zu klassifizieren. Die Sache, an die Sie sich erinnern sollten, ist, dass Sie bei der Bearbeitung von Loopback -Paketen in Ihrem Filter nicht "inbound" haben können. Es ist wichtig zu wissen, dass Ihr Computer möglicherweise andere IPs als 127.0.0.1 hat, wie eine von Ihrem Router zugewiesene Intranet -IP. Diese werden auch als Loopback -Pakete angesehen.
- Loopback -Pakete werden zweimal erfasst. Da wir keine Inbound -Loopback -Pakete haben, gelten alle Loopback -Pakete als ausgehender. So ungeschickt wird sie zweimal verarbeitet: Zum ersten Mal beim Senden und beim zweiten Mal beim Empfangen. Ein einfaches Beispiel ist, dass beim einfach "ausgehenden" Filter eine Verzögerung von 500 ms angewendet wird. Wenn Sie Localhost pingen, wäre es eine Verzögerung von 1000 ms. Sie können es um den Zielport und solche Dinge angeben. Es wäre jedoch einfacher, dies zu berücksichtigen und vorsichtig zu sein, wenn die Parameter festgelegt werden.
- Eingehende Paketförderung funktioniert nicht ständig. Wie bereits erwähnt, können Loopback -Inbound -Pakete nicht zurückgefordert werden. Das Problem ist, dass gelegentlich einige Pakete als eingehende Pakete klassifiziert werden können, auch wenn die Ziel -IP nicht Ihres Computers nicht ist. Dies betrifft nur Nicht-Loopback-Pakete. Wenn Sie nur an Localhost arbeiten, wird es in Ordnung. Das Ziel der zukünftigen Freisetzung ist es, zu diagnostizieren, was dies verursacht hat, und eine Lösung bereitzustellen.
- Das Filter kann nicht basierend auf dem Prozess -Systemweitnetzwerk erfasst wird als Funktion aufgeführt. Aber das ist wirklich, da es keine einfache Möglichkeit gibt, eine robuste Lösung zu bieten.
Ich bin immer offen für Beiträge, entweder in Form von Fehlerberichten, Fehlerbehebungen (sogar besser!) Oder eine verbesserte Testabdeckung.
Feature -Anfragen sind willkommen, können jedoch in einem Rückstand gehalten werden, je nachdem, wie umfangreich, machbar oder wünschenswert sie sind. Wenn eine Feature -Anfrage zu komplex ist, kann dies von Sponsoring abhängen, da ich nur begrenzte Ressourcen (Zeit und Geld) habe, um mich zu widmen.
Wenn Sie dieses Projekt unterstützen möchten, bin ich vielleicht daran interessiert, von Ihnen zu hören, also greifen Sie zu!
In Portugiesisch ist Carambolas die Pluralform von Carambola (= Starfruit). Der Begriff wird auch umgangssprachlich in bestimmten Regionen Brasiliens verwendet, um Erstaunen oder Ungeduld auszudrücken.
Vor Carambolas habe ich mindestens ein halbes Dutzend Versuche unternommen, meine Ideen in einem verwendbaren Projekt zu organisieren. Mit Carambolas entschied ich mich, eine Reihe von Prototypen zu erstellen, um über Designprobleme zu erfahren und verschiedene Ansätze zu testen. Jeder Prototyp hatte einen Codenamen, der durch einen Buchstaben und eine Nummer ab A1 gebildet wurde. Der Quellcode, der ursprünglich in diesem Repository importiert wurde, war die 75. Iteration des 9. Prototyps, daher A9.
Native Bibliotheken werden hauptsächlich aus Leistungsgründen bereitgestellt, daher sind sie völlig optional. Es wäre unangemessen gewesen, eine native Implementierung für jede mögliche Plattform bereitzustellen (denken Sie an alle Desktops, Mobile, Konsole, eingebettet ...) und würde sich ausschließlich auf native Bibliotheken verlassen, dass Zielplattformen nur eine Handvoll, möglicherweise nur Desktop (Windows, Linux und MacOS), auf nur eine Handvoll reduzieren würde. Den Faustregel muss also immer eine Fallback -Implementierung im verwalteten Code für jede von einer native Bibliothek implementierte Funktionen geben.
Da native Bibliotheken optional sind, kann das Programm nicht sagen, ob eine fehlende Datei da sein sollte oder nicht, weshalb kein Fehler für eine fehlende native Bibliothek geworfen oder protokolliert wird. Per Definition ist eine fehlende native Bibliothek nie ein Fehler.
Im Allgemeinen können Sie nicht. Und Sie sollten nicht, zumindest nicht aus API -Sicht. Für den Benutzer (oder den App -Programmierer) sollte es keine Rolle spielen, welche zugrunde liegende Implementierungsstrategie von einer Abhängigkeit in diesem Fall Carambolas angewendet wird. Diese Informationen können jedoch für die Bereitstellung relevant sein. Jedes Mal, wenn ein Interop -Objekt erstellt wird, das auch über einen automatischen Fallback verfügt, erstellt der Code eine indikative Protokollinformation. Beispielsweise erstellt Carambolas.net.socket eine Protokollinformation, die "mit carambolas.net.sockets.native.socket" ähnelt, wenn eine native Bibliothek für die zugrunde liegende Socket -Implementierung gefunden wird. Wenn Sie berücksichtigt werden, können Sie feststellen, ob Sie tatsächlich verwendet werden, ob sie tatsächlich verwendet werden.
Dies bedeutet, dass Sie eine native Bibliothek einsetzen, die entweder beschädigt oder für die falsche CPU -Architektur kompiliert wird.
Native Bibliotheken müssen mit ihren entsprechenden Interop-Baugruppen nebeneinander antreten, und obwohl Baugruppen für eine CPU-Architektur einmal zusammengestellt werden können, können native Bibliotheken dies nicht. Sie müssen mit der CPU -Architektur des laufenden Betriebssystems übereinstimmen, ansonsten werden sie als beschädigte Dateien behandelt und .NET löst ein System aus. BadimageFormatexception. Beachten Sie, dass dies nicht dasselbe ist wie der Versuch, eine Bibliothek zu laden, die nicht gefunden wird und per Definition kein Fehler ist.
Das Bandwidth-Delay-Produkt (BDP) ist das Produkt der Übertragungskapazität einer Netzwerkverbindung (in Bits pro Sekunde) und seiner Rundweg-Verzögerungszeit (in Sekunden). Es stellt die sehr maximale Datenmenge dar, die ein Netzwerk aufbewahren kann, bevor eine Bestätigung eintreffen kann.
Mit dem BDP können Netzwerke entsprechend oder unter einem bestimmten Schwellenwert klassifiziert werden. Netzwerke mit einem großen BDP werden als Long Fat Networks (LFNs) bezeichnet. LFNs können Netzwerke mit einer sehr großen durchschnittlichen Hin- und Rückfahrt (regad ohne Bandbreite, wie bei Satellitenverbindungen) oder einem breiten (hohen Bandbreiten) Netzwerk sein, das erheblich kleine Roundtrip-Zeiten (wie in Gigabit-Ethernet-Links) zeigt.
Weitere Informationen dazu finden Sie in der Wikipedia.
Ein Carammbolas.net.Socket -Objekt dient als Fassade für eine native Socket -Implementierung oder eine Fallback -Implementierung, die auf System.net.sockets.socket beruht. Es hilft, die Komplexität von Host- und Peer -Objekten zu entkoppeln und zu verringern. Weitere Informationen finden Sie in Doc/Readme-Carambolas.net.
System.net.ipaddress und System.net.ipendpoint sind veränderliche Objekte, die eine Reihe unnötiger Zuweisungen in allen aktuellen Implemationen von .NET Core- und .NET -Framework fördern. Carambolas.net.ipaddress und carambolas.net.ipendpoint sind unveränderliche Werttypen, die zur Reduzierung des GC -Drucks beitragen. Weitere Informationen finden Sie in Doc/Readme-Carambolas.net.
Aead mit Chacha20 und Poly1305 wird außerhalb des Boxs unterstützt. Benutzerdefinierte Strategien können implementiert werden, indem dem Host implementiert werden. Die einzigen Anforderungen sind:
Eine Benutzeranwendung ist frei, um ihre Daten vor dem Senden zu komprimieren, aber derzeit gibt es keinen Mechanismus, um eine automatische Komprimierung/Dekompression einzelner Nachrichten oder vollständiger Pakete bereitzustellen.
Alle Quellcode und alle Binärdateien, die zusammen mit einer Benutzeranwendung bereitgestellt werden, werden unter einer MIT -Lizenz lizenziert.
Carambolas.commandLineargumente basierte auf einem Artikel von Griffonrl mit Quellcode, der unter einer MIT -Lizenz mit zusätzlichen Ideen aus einem anderen Artikel von Jake Ginnivan veröffentlicht wurde, der auf der ursprünglichen Quelle erweitert wurde.
Carambolas.security.criptography.crc32c basierte auf CRC32.NET mit Gewalt unter einer MIT -Lizenz.
Carambolas.security.criptography.nacl wurde von David de Smet unter einer MIT -Lizenz auf NaCl.core erweitert und erweitert.
Die in Lua für Wireshark geschriebene Protokolldissektor ist im Rahmen einer GPLV3 -Lizenz erhältlich. Es soll nur als Eingabedatei für Wireshark verwendet werden, um die Funktionen zu erweitern und weitere Informationen zu UDP -Paketen anzuzeigen, die gemäß dem Carambolas -Netzwerkprotokoll formatiert sind. Daher ist es vollständig getrennt und interagiert, hängt in keiner Weise zu Quelldateien, Baugruppen oder nativen Bibliotheken ab oder leistet sie.