message-io
ist eine schnelle und benutzerfreundliche ereignisgesteuerte Netzwerkbibliothek. Die Bibliothek verwaltet den Betriebssystem-Socket intern und bietet dem Benutzer eine einfache Ereignisnachrichten-API. Außerdem können Sie damit nach einigen Regeln einen Adapter für Ihr eigenes Transportprotokoll erstellen und so die mühsame Asynchronität und Thread-Verwaltung an die Bibliothek delegieren.
Wenn Sie ein Problem bei der Nutzung der Bibliothek feststellen oder eine Idee zur Verbesserung haben, zögern Sie nicht, ein Problem zu eröffnen. Jeder Beitrag ist willkommen! Und denken Sie daran: mehr Koffein, produktiver!
Die Verwaltung von Sockets ist schwierig, da Sie mit Threads, Parallelität, Vollduplex, Codierung, E/A-Fehlern kämpfen müssen, die vom Betriebssystem ausgehen (die in manchen Situationen wirklich schwer zu verstehen sind) usw. Wenn Sie nicht blockierende Sockets verwenden, Es fügt eine neue Ebene der Komplexität hinzu: Synchronisieren Sie die Ereignisse, die asynchron vom Betriebssystem kommen.
message-io
bietet eine einfache Möglichkeit, mit all diesen oben genannten Problemen umzugehen und sie für Sie als Programmierer, der eine Anwendung mit seinen eigenen Problemen erstellen möchte, transparent zu machen. Zu diesem Zweck stellt Ihnen die Bibliothek eine einfache API mit zwei zu verstehenden Konzepten zur Verfügung: Nachrichten (die Daten, die Sie senden und empfangen) und Endpunkte (die Empfänger dieser Daten). Diese Abstraktion bietet auch die Möglichkeit, unabhängig vom verwendeten Transportprotokoll dieselbe API zu verwenden. Sie könnten den Transport Ihrer Anwendung buchstäblich in einer Zeile ändern.
wasm
wird nicht unterstützt, ist aber geplant).NodeHandler
zur Verwaltung aller Verbindungen (verbinden, abhören, entfernen, senden) und Signale (Timer, Priorität).NodeListener
zur Verarbeitung aller Signale und Ereignisse aus dem Netzwerk.std::io::Error
.message-io
verfügt nicht über den Transport, den Sie benötigen? Fügen Sie ganz einfach einen Adapter hinzu. Fügen Sie zu Ihrem Cargo.toml
hinzu (alle Transporte sind standardmäßig enthalten):
[ dependencies ]
message-io = " 0.18 "
Wenn Sie nur einen Teil der verfügbaren Transportbatterie nutzen möchten, können Sie diese anhand der zugehörigen Funktionen tcp
, udp
und websocket
auswählen. Um beispielsweise nur TCP und UDP einzubeziehen, fügen Sie Ihrer Cargo.toml
Folgendes hinzu:
[ dependencies ]
message-io = { version = " 0.18 " , default-features = false , features = [ " tcp " , " udp " ] }
Das folgende Beispiel ist der einfachste Server, der Nachrichten von den Clients liest und ihnen mit derselben Nachricht antwortet. Es ist in der Lage, den „Dienst“ für 3 verschiedene Protokolle gleichzeitig anzubieten.
use message_io :: node :: { self } ;
use message_io :: network :: { NetEvent , Transport } ;
fn main ( ) {
// Create a node, the main message-io entity. It is divided in 2 parts:
// The 'handler', used to make actions (connect, send messages, signals, stop the node...)
// The 'listener', used to read events from the network or signals.
let ( handler , listener ) = node :: split :: < ( ) > ( ) ;
// Listen for TCP, UDP and WebSocket messages at the same time.
handler . network ( ) . listen ( Transport :: FramedTcp , "0.0.0.0:3042" ) . unwrap ( ) ;
handler . network ( ) . listen ( Transport :: Udp , "0.0.0.0:3043" ) . unwrap ( ) ;
handler . network ( ) . listen ( Transport :: Ws , "0.0.0.0:3044" ) . unwrap ( ) ;
// Read incoming network events.
listener . for_each ( move |event| match event . network ( ) {
NetEvent :: Connected ( _ , _ ) => unreachable ! ( ) , // Used for explicit connections.
NetEvent :: Accepted ( _endpoint , _listener ) => println ! ( "Client connected" ) , // Tcp or Ws
NetEvent :: Message ( endpoint , data ) => {
println ! ( "Received: {}" , String :: from_utf8_lossy ( data ) ) ;
handler . network ( ) . send ( endpoint , data ) ;
} ,
NetEvent :: Disconnected ( _endpoint ) => println ! ( "Client disconnected" ) , //Tcp or Ws
} ) ;
}
Das folgende Beispiel zeigt einen Client, der eine Verbindung zum vorherigen Server herstellen kann. Es sendet jede Sekunde eine Nachricht an den Server und hört deren Echoantwort ab. Durch Ändern von Transport::FramedTcp
in Udp
oder Ws
wird der zugrunde liegende verwendete Transport geändert.
use message_io :: node :: { self , NodeEvent } ;
use message_io :: network :: { NetEvent , Transport } ;
use std :: time :: Duration ;
enum Signal {
Greet ,
// Any other app event here.
}
fn main ( ) {
let ( handler , listener ) = node :: split ( ) ;
// You can change the transport to Udp or Ws (WebSocket).
let ( server , _ ) = handler . network ( ) . connect ( Transport :: FramedTcp , "127.0.0.1:3042" ) . unwrap ( ) ;
listener . for_each ( move |event| match event {
NodeEvent :: Network ( net_event ) => match net_event {
NetEvent :: Connected ( _endpoint , _ok ) => handler . signals ( ) . send ( Signal :: Greet ) ,
NetEvent :: Accepted ( _ , _ ) => unreachable ! ( ) , // Only generated by listening
NetEvent :: Message ( _endpoint , data ) => {
println ! ( "Received: {}" , String :: from_utf8_lossy ( data ) ) ;
} ,
NetEvent :: Disconnected ( _endpoint ) => ( ) ,
}
NodeEvent :: Signal ( signal ) => match signal {
Signal :: Greet => { // computed every second
handler . network ( ) . send ( server , "Hello server!" . as_bytes ( ) ) ;
handler . signals ( ) . send_with_timer ( Signal :: Greet , Duration :: from_secs ( 1 ) ) ;
}
}
} ) ;
}
Klonen Sie das Repository und testen Sie das Ping-Pong -Beispiel (ähnlich dem README -Beispiel, aber mit mehr Vitaminen).
Führen Sie den Server aus:
cargo run --example ping-pong server tcp 3456
Führen Sie den Client aus:
cargo run --example ping-pong client tcp 127.0.0.1:3456
Sie können damit experimentieren, indem Sie den Transport ändern, mehrere Clients ausführen, die Verbindung trennen usw. Weitere Informationen finden Sie hier.
message-io
nicht hat? Fügen Sie einen Adapter hinzu! message-io
bietet zwei Arten von APIs. Die Benutzer-API , die mit message-io
selbst als Benutzer der Bibliothek kommuniziert, und die interne Adapter-API für diejenigen, die ihre Protokolladapter zur Bibliothek hinzufügen möchten.
Wenn ein Transportprotokoll zusätzlich zu mio
erstellt werden kann (was bei den meisten vorhandenen Protokollbibliotheken der Fall ist), können Sie es ganz einfach zu message-io
hinzufügen:
Fügen Sie Ihre Adapterdatei in src/adapters/<my-transport-protocol>.rs
hinzu, die die hier gefundenen Merkmale implementiert. Es enthält nur 8 obligatorische zu implementierende Funktionen (siehe Vorlage) und die Implementierung eines Adapters dauert etwa 150 Zeilen.
Fügen Sie ein neues Feld in der Transport
Enumeration in src/network/transport.rs hinzu, um Ihren neuen Adapter zu registrieren.
Das ist alles. Sie können Ihren neuen Transport mit der message-io
API wie jeden anderen verwenden.
Hoppla! Noch ein Schritt: Erstellen Sie eine Pull-Anfrage , damit jeder sie verwenden kann :)
message-io
Verwendet Ihr großartiges Projekt message-io
? Machen Sie eine Pull-Anfrage und fügen Sie sie der Liste hinzu!
message-io
hat das Hauptziel, die Dinge einfach zu halten. Das ist großartig, aber manchmal könnte diese Sichtweise die bereits komplexen Dinge noch komplexer machen.
Beispielsweise ermöglicht message-io
die Verarbeitung asynchroner Netzwerkereignisse ohne Verwendung eines async/await
Musters. Es reduziert die Komplexität bei der Verarbeitung von Einkommensnachrichten aus dem Netzwerk, was großartig ist. Dennoch führen die Anwendungen, die asynchrone Nachrichten lesen, tendenziell auch asynchrone Aufgaben für diese Ereignisse aus. Diese asynchrone Vererbung kann leicht auf Ihre gesamte Anwendung übertragen werden, da sie ohne ein Asynchron-/Wartemuster schwer zu warten oder zu skalieren ist. In solchen Fällen könnte tokio
vielleicht die bessere Option sein. Sie müssen sich mit mehr Low-Level-Netzwerkaufgaben befassen, gewinnen aber an Organisation und Thread-/Ressourcenverwaltung.
Ein ähnliches Problem kann bei der Knotennutzung von message-io
auftreten. Da ein Knoten unabhängig als Client/Server oder als beides verwendet werden kann, können Sie problemlos mit der Erstellung von Peer-to-Peer-Anwendungen beginnen. Tatsächlich ist dies eine der Absichten von message-io
. Wenn Ihr Ziel jedoch skaliert, treten Probleme im Zusammenhang mit diesem Muster auf, mit denen Sie umgehen müssen, und Bibliotheken wie libp2p
verfügen über eine große Auswahl an Tools, die Ihnen bei der Erreichung dieses Ziels helfen.
Natürlich handelt es sich hier nicht um eine Verzichtserklärung auf die Nutzung der Bibliothek (ich nutze sie!), es geht vielmehr darum, ehrlich über ihre Fähigkeiten zu sein und Sie zum richtigen Tool zu führen, je nachdem, wonach Sie suchen.
Zusammenfassend:
message-io
einfacher!tokio
, libp2p
oder andere, um mehr Kontrolle darüber zu haben.