11 unstable releases (5 breaking)
0.7.0 |
|
---|---|
0.7.0-alpha.2 | Aug 16, 2024 |
0.7.0-alpha.1 | Jul 30, 2024 |
0.6.0 | Jul 30, 2024 |
0.1.4 | Oct 9, 2023 |
#222 in Network programming
55 downloads per month
Used in 7 crates
78KB
776 lines
aeronet
A light-as-air client/server transport library with first-class support for Bevy, providing a consistent API which can be implemented by different transport mechanisms.
Try the example!
Start the server:
cargo run --bin move_box_server
Run a native desktop client:
cargo run --bin move_box_client
Run the client in a browser:
cargo install wasm-server-runner
cargo run --bin move_box_client --target wasm32-unknown-unknown
And connect to http://[::1]:25565
.
See the examples folder for the source code.
Transport
The main purpose of this crate is to provide an API for transmitting messages between a client and
a server over any type of connection - in-memory channels, networked, WASM, etc. This is done
through the traits ClientTransport
and ServerTransport
.
The current transport implementations available are:
aeronet_channel
- using in-memory MPSC channels- Useful for non-networked scenarios, such as a local singleplayer server
- Targets: Native + WASM
cargo run --package aeronet_channel --example echo --features "bevy"
aeronet_webtransport
- using the WebTransport protocol, based on QUIC- Good choice for a general transport implementation
- Targets: Native (client + server) + WASM (client)
cargo run --package aeronet_webtransport --example echo_client --features "bevy dangerous-configuration"
cargo run --package aeronet_webtransport --example echo_client --features "bevy dangerous-configuration" --target wasm32-unknown-unknown
- Requires
wasm-server-runner
to be installed
- Requires
cargo run --package aeronet_webtransport --example echo_server --features "bevy"
aeronet_steam
- using Steam's NetworkingSockets API- STILL WIP
- Targets: Native
cargo run --package aeronet_steam --example echo_client --features "bevy"
cargo run --package aeronet_steam --example echo_server --features "bevy"
Goals
This crate aims to be:
- Generic over as many transports as possible
- You should be able to plug nearly anything in as the underlying transport layer, and have things work
- To achieve this, aeronet provides its own implementation of certain protocol elements such as
fragmentation and reliable messages - see
aeronet_proto
- Integrated with Bevy
- Built with apps and games in mind, the abstractions chosen closely suit Bevy's app model, and likely other similar frameworks
- Simple in terms of API
- The complexity of the underlying transport is abstracted away, which allows for both flexibility in implementation, and less cognitive load on the API user
- Configuration options are still exposed, however there are always a set of sane defaults
- Comfortable for non-async code
- This crate abstracts away transport-related async code, and exposes a simpler sync API.
- Lightweight and have a small footprint
- The crate minimizes the amount of data copied by using
Bytes
, reducing allocations - Features such as reliability and ordering are implemented with a small memory footprint
- The crate minimizes the amount of data copied by using
This crate does not aim to be:
- A high-level app networking library, featuring replication, rollback, etc.
- This crate only concerns the transport of data payloads, not what the payloads actually contain
- An async library
#![no_std]
- A non-client-to-server networking library (e.g. peer-to-peer)
- A client is expected to only have at most 1 connection to a server - although this server could also be a client who is running the same app
Overview
Messages
The smallest unit of transmission that the API exposes is a message. A message is represented as a
Bytes
- a container for a byte sequence which allows zero-copy networking code. It is up to the
user to give meaning to these bytes.
Lanes
Lanes define the manner in which a message is delivered to the other side, such as
unreliable, reliable ordered, etc. These are similar to streams or channels in some protocols,
but lanes are abstractions over the manner of delivery, rather than the individual stream or
channel. The types of lanes that are supported, and therefore what guarantees are given, are listed
in LaneKind
.
Note that if a transport does not support lanes, then it inherently guarantees the strongest guarantees provided by lanes - that is, communication is always reliable-ordered.
Typically, a transport implementation will require you to pass a configuration on creation, which defines which lanes are available to the transport, and what their properties are (i.e. is it reliable, ordered, etc).
Bevy plugin
Feature flag: bevy
This crate provides some useful items and types for working with transports, which can be added to your app as a resource. However, note that no plugins are provided - instead, it is your responsibility to drive the transport event loop manually.
Conditioning
Feature flag: condition
- depends on getrandom
, which may not work in WASM
A common strategy used for ensuring that your network code is robust against failure is to add
artificial packet loss and delays. This crate provides a utility for this via the condition
module.
Protocol
Crate: aeronet_proto
This crate provides a reusable set of transport-level abstractions which can be used by transport implementations, if they do not support certain features already. This makes providing a new transport implementation easy, since you just plug in these features into the underlying byte stream or whatever other mechanism your transport uses.
bevy_replicon
integration
Crate: aeronet_replicon
Using this crate, you can plug any aeronet transport into bevy_replicon
as a backend, giving you
high-level networking features such as entity replication, while still being free to use any
transport implementation under the hood.
Getting started
Using an existing transport
If you want to use one of the transports already supported (which is probably what you want to do), add both this crate and the transport implementation crate as dependencies to your project:
[dependencies]
aeronet = "version"
aeronet_whatever_transport_impl = "version"
The version of this crate is synced between all official subcrates of aeronet - use the same version that you use for aeronet for your transport, and you're good to go.
To create a value for your given transport, and how exactly to configure it, see the transport's
Getting Started section in the readme. If using Bevy, you should insert the transport as a
resource into your app. Otherwise, keep a hold of your transport somewhere where you can use it in
your main update loop - you will need to manually drive it by poll
ing.
You can use the traits ClientTransport
and ServerTransport
to control your client or server,
such as sending and receiving messages.
Client and server state
This crate abstracts a client's connection into either disconnected, connecting, or connected; and servers into closed, opening, or open. By default, clients start disconnected, and servers start closed - you must manually start a connection or open the server, by providing a configuration such as address to connect to, port to open on, etc. This will vary depending on the transport implementation.
See ClientState
and ServerState
for more info.
Managing the connection
After a connection is established:
- use
send
to buffer up a message for sending from this peer to the other side - use
flush
to flush all buffered messages and actually send them across the transport - use
poll
to update the internal state of the transport and receive events about what happened
It is recommended that you use send
to buffer up messages for sending during your app's update,
then use poll
and flush
at the end of each update to finalize the update.
It is up to you to encode and decode your own data into the Bytes
.
use aeronet::bytes::Bytes;
use aeronet::client::{ClientEvent, ClientTransport};
use aeronet::lane::LaneIndex;
#[derive(Debug, Clone, Copy)]
enum AppLane {
HighPriority,
LowPriority,
}
impl From<AppLane> for LaneIndex {
fn from(value: AppLane) -> Self {
match value {
AppLane::HighPriority => LaneIndex::from_raw(0),
AppLane::LowPriority => LaneIndex::from_raw(1),
}
}
}
# fn run(mut client: impl ClientTransport, delta_time: web_time::Duration) {
let message: Bytes = Bytes::from_static(b"hello world");
client.send(message, AppLane::HighPriority).unwrap();
client.flush().unwrap();
for event in client.poll(delta_time) {
match event {
ClientEvent::Recv { msg, lane } => {
let msg = String::from_utf8(Vec::from(msg)).unwrap();
println!("Received on {lane:?}: {msg}");
}
_ => unimplemented!()
}
}
# }
Bevy support
bevy |
aeronet |
---|---|
0.14 | 0.7 |
0.13 | 0.6 |
Dependencies
~0.5–45MB
~678K SLoC