Skip to content

Blocking API EN

b23r0 edited this page Oct 12, 2026 · 1 revision

English · 简体中文

Blocking API

Available since 1.3.0. It uses the existing asynchronous protocol implementation; it does not introduce a second RakNet stack.

Client

[dependencies]
rust-raknet = { version = "1.4.0", features = ["blocking"] }
use rust_raknet::{blocking::RaknetRuntime, Reliability};
use std::time::Duration;

fn main() -> rust_raknet::blocking::Result<()> {
    let runtime = RaknetRuntime::new()?;
    let address = "127.0.0.1:19132".parse().unwrap();
    let socket = runtime.connect_timeout(&address, Duration::from_secs(10))?;
    socket.send_timeout(&[0xfe, 1, 2, 3], Reliability::ReliableOrdered,
                        Duration::from_secs(2))?;
    let reply = socket.recv_timeout(Duration::from_secs(2))?;
    println!("Echo: {reply:?}");
    socket.flush_timeout(Duration::from_secs(2))?;
    socket.close()
}

Run against the async echo server. Both endpoints must share an isolated network. Messages still require the 0xfe prefix.

Listener

use rust_raknet::{blocking::RaknetRuntime, Reliability};

fn main() -> rust_raknet::blocking::Result<()> {
    let runtime = RaknetRuntime::new()?;
    let address = "127.0.0.1:19132".parse().unwrap();
    let mut listener = runtime.bind(&address)?;
    listener.listen()?;
    let socket = listener.accept()?;
    let message = socket.recv()?;
    socket.send(&message, Reliability::ReliableOrdered)?;
    socket.flush()?;
    socket.close()?;
    listener.close()
}

This is a one-connection example. For multiple peers, keep accepting while handing sessions to bounded application workers; do not block the accept loop on a slow session.

Runtime and threading

  • RaknetRuntime::new() starts one network worker. with_worker_threads(NonZeroUsize) selects the worker count.
  • Clone a runtime to share its workers across clients and listeners; sockets keep the runtime alive. There is no global runtime and no new runtime per send.
  • Workers keep receiving, acknowledging and retrying while the application is between calls.
  • Blocking operations, including runtime construction, reject calls within a Tokio runtime with Error::AsyncContext. Use async APIs there. A bounded spawn_blocking task can construct/use blocking handles outside that context, but native async calls avoid the adapter.
  • Receives share a serialized consumer. Multiple receive callers compete for messages; they do not each receive a copy. Serialize dependent concurrent sends on the same ordering channel.
  • A blocking receive stalls the caller. For a game engine, keep networking on a dedicated worker and exchange messages through bounded queues. No Sans-I/O, try_recv or Bevy plugin is provided.

Deadlines and cleanup

Timeout methods exist for connect, ping, accept, borrowed/owned sends, borrowed batch sends, borrowed/owned receives, borrowed batch receive and flush. There is no timeout variant for every channel/batch API; consult the complete method index.

A timeout stops waiting, not already accepted delivery. A batch can send a prefix before timing out; blindly retrying can duplicate application messages. flush waits for transport ACKs, not business processing. Stop producers, flush with a deadline, then close. Dropping the final runtime owner shuts down background work and is not graceful delivery.

blocking can combine with send-policy and recovery-policy. Its policy getters/setters are synchronous; setters return blocking::Result, and send_options() returns Result<Option<SendOptions>>.

API reference · Separate blocking benchmark

Clone this wiki locally