Crate veloren_network
source · [−]Expand description
Crate to handle high level networking of messages with different requirements and priorities over a number of protocols
To start with the veloren_network
crate you should focus on the 3
elementar structs Network
, Participant
and Stream
.
Say you have an application that wants to communicate with other application
over a Network or on the same computer. Now each application instances the
struct Network
once with a new Pid
. The Pid is necessary to identify
other Networks
over the network protocols (e.g. TCP, UDP, QUIC, MPSC)
To connect to another application, you must know it’s ConnectAddr
. One
side will call connect
, the other connected
. If successful both
applications will now get a Participant
.
This Participant
represents the connection between those 2 applications.
over the respective ConnectAddr
and with it the chosen network
protocol. However messages can’t be send directly via Participants
,
instead you must open a Stream
on it. Like above, one side has to call
open
, the other opened
. Streams
can have a different priority
and Promises
.
You can now use the Stream
to send
and recv
in both directions.
You can send all kind of messages that implement serde
.
As the receiving side needs to know the format, it sometimes is useful to
always send a specific Enum and then handling it with a big match
statement This create makes heavily use of async
, except for send
which returns always directly.
For best practices see the examples
folder of this crate containing useful
code snippets, a simple client/server below. Of course due to the async
nature, no strict client server separation is necessary
Examples
use std::sync::Arc;
use tokio::{join, runtime::Runtime, time::sleep};
use veloren_network::{ConnectAddr, ListenAddr, Network, Pid, Promises};
// Client
async fn client(runtime: &Runtime) -> std::result::Result<(), Box<dyn std::error::Error>> {
sleep(std::time::Duration::from_secs(1)).await; // `connect` MUST be after `listen`
let client_network = Network::new(Pid::new(), runtime);
let server = client_network
.connect(ConnectAddr::Tcp("127.0.0.1:12345".parse().unwrap()))
.await?;
let mut stream = server
.open(4, Promises::ORDERED | Promises::CONSISTENCY, 0)
.await?;
stream.send("Hello World")?;
Ok(())
}
// Server
async fn server(runtime: &Runtime) -> std::result::Result<(), Box<dyn std::error::Error>> {
let server_network = Network::new(Pid::new(), runtime);
server_network
.listen(ListenAddr::Tcp("127.0.0.1:12345".parse().unwrap()))
.await?;
let client = server_network.connected().await?;
let mut stream = client.opened().await?;
let msg: String = stream.recv().await?;
println!("Got message: {}", msg);
assert_eq!(msg, "Hello World");
Ok(())
}
fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
let runtime = Runtime::new().unwrap();
runtime.block_on(async {
let (result_c, result_s) = join!(client(&runtime), server(&runtime),);
result_c?;
result_s?;
Ok(())
})
}
Modules
Structs
Use the Network
to create connections to other Participants
Support struct used for uniquely identifying Participant
over the
Network
.
Streams
represents a channel to send n
messages with a certain priority
and Promises
. messages need always to be send between 2 Streams
.
All Parameters of a Stream, can be used to generate RawMessages
Enums
Represents a Tcp, Quic, Udp or Mpsc connection address
All possible Errors that can happen during Handshake InitProtocol
Represents a Tcp, Quic, Udp or Mpsc listen address
Error type thrown by Networks
connect
Error type thrown by Networks
methods
Error type thrown by Participants
methods
Error type thrown by Streams
methods
A Compression Error should only happen if a client sends malicious code.
A Deserialize Error probably means you are expecting Type X while you
actually got send type Y.