Dev-Install — in 5 Minuten zum ersten Sample
Vom leeren Projekt zum ersten Pub/Sub-Roundtrip auf dem Loopback: ein neues Cargo-Projekt, drei Crates als Dependency, ~15 Zeilen Code, cargo run. Danach: Feature-Flag-Builds (warum drei?), Dev-Toolchain, Config-Knobs und Plattform-Support. Diese Page ist Rust-fokussiert — für C++, C#, Java, Python, TypeScript oder C-FFI siehe Sprach-Auswahl.
Welche Sprache?
ZeroDDS ist Pure-Rust unter der Haube, mit nativen Bindings für 7 weitere Sprachen. Jede hat ihren eigenen 5-Minuten-Quickstart — Install, Pub/Sub-Code, Run.
| Sprache | Install | Voraussetzungen | Eigenheiten | Quickstart |
|---|---|---|---|---|
| Rust (Primärpfad) | cargo add zerodds-dcps | Rust 1.88+ · Edition 2024 | Pure-Rust · async/streams · no_std-tauglich | unten ↓ |
| C++ | -lzerodds + headers | C++17 · libzerodds.so | DDS-PSM-Cxx 1.0 · ABI-stabil · zerodds-idlc --cpp | /bindings/cpp/ → |
| C# / .NET | dotnet add package ZeroDDS | .NET 8 + netstandard2.1 | NativeAOT · async/await · Source-Generators | /bindings/csharp/ → |
| Java | Maven / Gradle | JDK 17+ (21+ für Virtual-Threads) | Pure-Java · org.omg.dds.* · kein JNI | /bindings/java/ → |
| Python | pip install zerodds | CPython 3.8–3.14 (abi3-py38) | @idl_struct · AsyncIO · QoS-Builder | /bindings/python/ → |
| TypeScript (Node) | npm install @zerodds/node | Node 18 LTS+ | N-API · strict TS · async/streams | /bindings/typescript-node/ → |
| TypeScript (Browser) | npm install @zerodds/wasm | Chrome 89+ · Firefox 89+ · Safari 15+ | WASM · WebSocket-Bridge nötig | /bindings/typescript-wasm/ → |
| C-FFI | -lzerodds + zerodds.h | C99+ oder C-Interop | Stable ABI · für Go, Zig, Ada, MATLAB, … | /bindings/c-ffi/ → |
Die Rust-Page (unten) ist gleichzeitig die Pure-Rust-Stack-Übersicht — Feature-Flags, Dev-Toolchain, Config, Plattform-Support. Wer in einer anderen Sprache anfängt, geht direkt zur Sprach-Page; die meisten Sections darunter (Config, Plattformen, Dev-Toolchain) gelten parallel.
5-Minuten-Quickstart (Rust)
Ein neues Cargo-Projekt, drei Dependencies, ein Publisher und ein Subscriber im selben Prozess. Läuft auf jedem System mit Rust 1.88+, ohne Setup.
1 · Cargo-Projekt + Dependencies
cargo new zerodds-hello --bin
cd zerodds-hello
Cargo.toml:
[package]
name = "zerodds-hello"
version = "0.1.0"
edition = "2024"
[dependencies]
zerodds-dcps = "1.0.0-rc.3"
Das ist alles. zerodds-dcps zieht alle benötigten Layer-Crates transitiv (foundation, cdr, qos, types, rtps, discovery, transport, transport-udp).
2 · Erste Pub/Sub-Schleife
src/main.rs:
use std::time::Duration;
use zerodds_dcps::*;
fn main() -> Result<()> {
let factory = DomainParticipantFactory::instance();
let participant = factory.create_participant(0, DomainParticipantQos::default())?;
let topic = participant.create_topic::<RawBytes>("Chatter", TopicQos::default())?;
let publisher = participant.create_publisher(PublisherQos::default());
let subscriber = participant.create_subscriber(SubscriberQos::default());
let writer = publisher.create_datawriter::<RawBytes>(&topic, DataWriterQos::default())?;
let reader = subscriber.create_datareader::<RawBytes>(&topic, DataReaderQos::default())?;
writer.wait_for_matched_subscription(1, Duration::from_secs(5))?;
reader.wait_for_matched_publication(1, Duration::from_secs(5))?;
writer.write(&RawBytes::new(b"hello".to_vec()))?;
reader.wait_for_data(Duration::from_secs(3))?;
for sample in reader.take()? {
println!("got: {:?}", sample.data);
}
Ok(())
}
▶ Runnable example: rust-dev-install-hello
3 · Bauen + laufen
cargo run --release
Erwartete Ausgabe: got: [104, 101, 108, 108, 111] (das "hello" als bytes). Wenn das läuft, ist der Stack komplett funktional — Discovery + RTPS + UDP-Loopback + DCPS-API.
Cargo zieht erst die Welt: ZeroDDS hat ~90 Workspace-Crates, der erste cargo build kompiliert ein paar hundert MB an Abhängigkeiten. Plane 1-2 Min für den ersten Build ein, danach läuft inkrementell in <1 s.
Feature-Flags — warum drei Builds
ZeroDDS-Crates haben drei Build-Profile, die unterschiedliche Plattform-Anforderungen bedienen. Default-Feature ist std — der Normalfall für Server, Desktop, Container.
| Feature | Default? | Plattform | Was es bringt | Wann nutzen |
|---|---|---|---|---|
std | ✓ | Linux · macOS · Windows · *BSD | Volle Standard-Library, Thread-Pool, OS-Sockets, Filesystem. | Server, Desktop, Container — der Normalfall. |
alloc | — | Embedded mit Allocator (Tock-OS, RTOS mit alloc) | Heap erlaubt (Vec, String), aber kein std (kein Threads, kein FS). | MCU mit RTOS, der einen Allocator bereitstellt. Cortex-M7/A-Class. |
safety | — | alle (orthogonal zu std/alloc) | Extra Runtime-Checks: Panic-on-Drift bei internen Invarianten, strikte Bounds-Checks, Tagged-State-Machines. | Compliance-Builds (CRA-Audit, ISO-26262-Vorbereitung), Pre-Production-Härtung. |
| (no default-features) | — | Freestanding · Bare-Metal · #![no_std] | Strikter no_std, kein Heap. Nur konst-evaluierbare Surfaces. | Cortex-M0/M3-Class ohne Allocator, RTOS-Kernel-Bibliotheken. |
Beispiele:
# Server-Build (Default)
zerodds-dcps = "1.0.0-rc.3"
# Embedded mit Allocator (alloc + safety)
zerodds-foundation = { version = "1.0.0-rc.3", default-features = false, features = ["alloc", "safety"] }
zerodds-cdr = { version = "1.0.0-rc.3", default-features = false, features = ["alloc"] }
# Strict no_std (Bare-Metal)
zerodds-foundation = { version = "1.0.0-rc.3", default-features = false }
zerodds-cdr = { version = "1.0.0-rc.3", default-features = false }
Wichtig: der volle DCPS-Stack (zerodds-dcps) braucht std (Threads für Discovery, OS-Sockets für UDP). Die Layer-1-Crates (foundation, cdr, qos, types) laufen no_std-fähig — für Embedded baut man typisch nur die Encoder/Decoder ein und nutzt eine externe Transport-Brücke.
Dev-Toolchain
Was du auf dem Dev-System brauchst.
Rust
# rustup falls noch nicht da
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# MSRV explizit setzen (Workspace-Wert)
rustup install 1.88
rustup default 1.88
# Komponenten
rustup component add clippy rustfmt rust-src
System-Pakete
ZeroDDS hat sehr wenige System-Dependencies; das meiste ist Pure-Rust.
| Plattform | Pakete | Warum |
|---|---|---|
| Ubuntu/Debian | build-essential pkg-config libssl-dev | Linker, OpenSSL für DDS-Security-Tests |
| Fedora/RHEL | gcc pkg-config openssl-devel | dito |
| macOS | Xcode-CLT (xcode-select --install) | Linker, macOS-SDK |
| Windows | Visual Studio Build Tools (C++ Workload) | MSVC-Linker |
Optional — Cross-Vendor-Tests
# Linux: Cyclone DDS für Live-Interop-Tests
sudo apt install cyclonedds-tools # liefert ddsperf, ddsls
# macOS via Homebrew
brew install cyclonedds
Damit laufen die crates/discovery/tests/cyclone_live_* Cross-Vendor-Tests; ohne werden sie geskipped.
Editor-Setup
- VS Code:
rust-analyzer-Extension. Im Workspace funktioniert es out-of-the-box (90+ Crates indexieren ~30 s beim ersten Open). - JetBrains: RustRover oder IntelliJ + Rust-Plugin.
- Vim/Neovim:
rust-analyzervia LSP-Client (coc.nvim, nvim-lspconfig). - Format-on-Save:
rustfmtmit Workspace-Default (rustfmt.tomlim Root).
Runtime-Config — was Devs wirklich anpassen
Install ist nicht nur Build — die meisten Probleme entstehen bei der Runtime-Konfiguration. Was sind die wichtigen Knobs?
Domain-ID
Alle Participants im gleichen Domain sprechen miteinander, alle anderen sind unsichtbar. Default 0 ist OK für Dev — produktiv pro Tenant/Stage eine eigene ID:
let participant = factory.create_participant(42, DomainParticipantQos::default())?;
Port-Mapping folgt DDSI-RTPS §9.6.1.4: port = 7400 + 250 * domain_id. Maximum-Domain-ID ist 232 (sonst >65535-Port).
Discovery-Multicast
SPDP nutzt per Default Multicast 239.255.0.1. Klappt auf LAN out-of-the-box. Probleme: Container-Netzwerke (Docker-Bridge blockt Multicast), Cross-Subnet (Router-Konfig nötig), Cloud-VPC (kein Multicast).
Wenn Multicast nicht geht: TCP-Backend + Static-Peers (siehe Transport-Tuning Rezept 2).
Fast-Discovery für Dev-Loops
Default-Discovery-Heartbeat ist 1 s. Für Dev-Loops (run, write, exit, run) zu langsam. Fast-Mode:
use zerodds_dcps::runtime::RuntimeConfig;
let cfg = RuntimeConfig {
tick_period: Duration::from_millis(20),
spdp_period: Duration::from_millis(100),
..RuntimeConfig::default()
};
let participant = factory.create_participant_with_config(0, DomainParticipantQos::default(), cfg)?;
▶ Runnable example: rust-dev-install-runtimeconfig
Damit ist Match-Latenz unter 200 ms. Nicht produktiv — 10× mehr Discovery-Traffic.
Logging
ZeroDDS nutzt tracing. Im Dev:
# Cargo.toml
tracing-subscriber = "0.3"
# main.rs
fn main() {
tracing_subscriber::fmt().with_max_level(tracing::Level::DEBUG).init();
// ... rest
}
# CLI
RUST_LOG=zerodds=debug cargo run
Strukturiertes Logging mit Span-Trees zeigt Discovery-Flow, Sample-Path, Retransmits.
QoS
Out of the box gelten die DDS-Spec-Defaults (§2.2.3.14, siehe QoS Reference): Writer=Reliable, Reader=BestEffort, History=KeepLast(1), Durability=Volatile. Weil der Reader per Default BestEffort anfordert, ist die effektive Zustellung best-effort — für garantierte Zustellung setzt du den Reader explizit auf Reliable. Für State-Topics zusätzlich Durability=TransientLocal, damit Late-Joiner den letzten Wert sehen. Fertige Profile: QoS Cookbook.
Aus dem Source bauen
Für Mitarbeit am Stack oder lokale Patches.
git clone https://github.com/zero-objects/zero-dds.git
cd zero-dds
cargo build --workspace --release
cargo test --workspace
Erwartung:
- Erster Build: 5-10 Min auf einem 8-Core, je nach Disk.
- Inkrementell: <1 s pro Crate.
- Volle Test-Suite: ~3-5 Min (~5400 Tests).
Pre-Commit-Checks (Memory: vor jedem Push laufen lassen):
cargo fmt --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo run -p dds-lint -- check crates/
Crates als path-Dep für Patches:
# Cargo.toml im konsumierenden Projekt
[patch.crates-io]
zerodds-foundation = { path = "/home/you/zero-dds/crates/foundation" }
zerodds-dcps = { path = "/home/you/zero-dds/crates/dcps" }
Plattform-Support
| Tier | Plattform | Status | CI |
|---|---|---|---|
| Tier-1 | Linux x86_64 (Ubuntu 24.04, Debian 12) | ✓ alle Tests | jeder PR |
| Tier-1 | Linux aarch64 (Ubuntu 24.04) | ✓ alle Tests | jeder PR |
| Tier-2 | macOS aarch64 (≥14.0) | ✓ manuell verifiziert | release-cycle |
| Tier-2 | Windows x86_64 (≥10) | ✓ manuell verifiziert | release-cycle |
| Tier-3 | FreeBSD 14, OpenBSD 7.5 | ~ Best-Effort (community) | — |
| Tier-3 | RTOS/Embedded (no_std + alloc) | ~ Layer-1 only (foundation/cdr/qos/types) | — |
Was als nächstes
- Topic-Type via IDL: statt
RawBytestypisierte Messages →idlcCompiler. - Cross-Process Pub/Sub: zwei
cargo run-Prozesse auf gleicher Domain-ID, eine Maschine. - Cross-Vendor: ZeroDDS Subscriber gegen Cyclone DDS Publisher → siehe Transport-Tuning.
- QoS-Tuning: nicht-Default-QoS für Late-Joiner, Failover, Realtime → QoS Cookbook.
- Security aktivieren:
--features security→ Security Plugin-Chain.
Dev Install — first sample in 5 minutes
From an empty project to the first pub/sub roundtrip on loopback: a new Cargo project, three crates as a dependency, ~15 lines of code, cargo run. Then: feature-flag builds (why three?), dev toolchain, config knobs and platform support. This page is Rust-focused — for C++, C#, Java, Python, TypeScript or C-FFI see the language picker.
Which language?
ZeroDDS is pure Rust under the hood, with native bindings for 7 more languages. Each has its own 5-minute quickstart — install, pub/sub code, run.
| Language | Install | Prerequisites | Specifics | Quickstart |
|---|---|---|---|---|
| Rust (primary path) | cargo add zerodds-dcps | Rust 1.88+ · Edition 2024 | pure Rust · async/streams · no_std-capable | below ↓ |
| C++ | -lzerodds + headers | C++17 · libzerodds.so | DDS-PSM-Cxx 1.0 · ABI-stable · zerodds-idlc --cpp | /bindings/cpp/ → |
| C# / .NET | dotnet add package ZeroDDS | .NET 8 + netstandard2.1 | NativeAOT · async/await · source generators | /bindings/csharp/ → |
| Java | Maven / Gradle | JDK 17+ (21+ for virtual threads) | pure Java · org.omg.dds.* · no JNI | /bindings/java/ → |
| Python | pip install zerodds | CPython 3.8–3.14 (abi3-py38) | @idl_struct · AsyncIO · QoS builder | /bindings/python/ → |
| TypeScript (Node) | npm install @zerodds/node | Node 18 LTS+ | N-API · strict TS · async/streams | /bindings/typescript-node/ → |
| TypeScript (browser) | npm install @zerodds/wasm | Chrome 89+ · Firefox 89+ · Safari 15+ | WASM · WebSocket bridge needed | /bindings/typescript-wasm/ → |
| C-FFI | -lzerodds + zerodds.h | C99+ or C interop | stable ABI · for Go, Zig, Ada, MATLAB, … | /bindings/c-ffi/ → |
The Rust page (below) is at the same time the pure-Rust stack overview — feature flags, dev toolchain, config, platform support. If you start in another language, go straight to the language page; most sections below it (config, platforms, dev toolchain) apply in parallel.
5-minute quickstart (Rust)
A new Cargo project, three dependencies, a publisher and a subscriber in the same process. Runs on any system with Rust 1.88+, no setup.
1 · Cargo project + dependencies
cargo new zerodds-hello --bin
cd zerodds-hello
Cargo.toml:
[package]
name = "zerodds-hello"
version = "0.1.0"
edition = "2024"
[dependencies]
zerodds-dcps = "1.0.0-rc.3"
That's all. zerodds-dcps pulls in all required layer crates transitively (foundation, cdr, qos, types, rtps, discovery, transport, transport-udp).
2 · First pub/sub loop
src/main.rs:
use std::time::Duration;
use zerodds_dcps::*;
fn main() -> Result<()> {
let factory = DomainParticipantFactory::instance();
let participant = factory.create_participant(0, DomainParticipantQos::default())?;
let topic = participant.create_topic::<RawBytes>("Chatter", TopicQos::default())?;
let publisher = participant.create_publisher(PublisherQos::default());
let subscriber = participant.create_subscriber(SubscriberQos::default());
let writer = publisher.create_datawriter::<RawBytes>(&topic, DataWriterQos::default())?;
let reader = subscriber.create_datareader::<RawBytes>(&topic, DataReaderQos::default())?;
writer.wait_for_matched_subscription(1, Duration::from_secs(5))?;
reader.wait_for_matched_publication(1, Duration::from_secs(5))?;
writer.write(&RawBytes::new(b"hello".to_vec()))?;
reader.wait_for_data(Duration::from_secs(3))?;
for sample in reader.take()? {
println!("got: {:?}", sample.data);
}
Ok(())
}
▶ Runnable example: rust-dev-install-hello
3 · Build + run
cargo run --release
Expected output: got: [104, 101, 108, 108, 111] (the "hello" as bytes). If that runs, the stack is fully functional — discovery + RTPS + UDP loopback + DCPS API.
Cargo pulls the world first: ZeroDDS has ~90 workspace crates; the first cargo build compiles a few hundred MB of dependencies. Plan 1-2 min for the first build, then incremental runs in <1 s.
Feature flags — why three builds
ZeroDDS crates have three build profiles that serve different platform requirements. The default feature is std — the normal case for servers, desktops, containers.
| Feature | Default? | Platform | What it gives | When to use |
|---|---|---|---|---|
std | ✓ | Linux · macOS · Windows · *BSD | Full standard library, thread pool, OS sockets, filesystem. | Servers, desktops, containers — the normal case. |
alloc | — | Embedded with an allocator (Tock-OS, RTOS with alloc) | Heap allowed (Vec, String), but no std (no threads, no FS). | An MCU with an RTOS that provides an allocator. Cortex-M7/A-class. |
safety | — | all (orthogonal to std/alloc) | Extra runtime checks: panic-on-drift for internal invariants, strict bounds checks, tagged state machines. | Compliance builds (CRA audit, ISO-26262 preparation), pre-production hardening. |
| (no default features) | — | Freestanding · bare metal · #![no_std] | Strict no_std, no heap. Only const-evaluable surfaces. | Cortex-M0/M3-class without an allocator, RTOS kernel libraries. |
Examples:
# server build (default)
zerodds-dcps = "1.0.0-rc.3"
# embedded with allocator (alloc + safety)
zerodds-foundation = { version = "1.0.0-rc.3", default-features = false, features = ["alloc", "safety"] }
zerodds-cdr = { version = "1.0.0-rc.3", default-features = false, features = ["alloc"] }
# strict no_std (bare metal)
zerodds-foundation = { version = "1.0.0-rc.3", default-features = false }
zerodds-cdr = { version = "1.0.0-rc.3", default-features = false }
Important: the full DCPS stack (zerodds-dcps) needs std (threads for discovery, OS sockets for UDP). The layer-1 crates (foundation, cdr, qos, types) are no_std-capable — for embedded you typically build in only the encoders/decoders and use an external transport bridge.
Dev toolchain
What you need on the dev system.
Rust
# rustup if not already there
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# set the MSRV explicitly (workspace value)
rustup install 1.88
rustup default 1.88
# components
rustup component add clippy rustfmt rust-src
System packages
ZeroDDS has very few system dependencies; most of it is pure Rust.
| Platform | Packages | Why |
|---|---|---|
| Ubuntu/Debian | build-essential pkg-config libssl-dev | Linker, OpenSSL for DDS-Security tests |
| Fedora/RHEL | gcc pkg-config openssl-devel | ditto |
| macOS | Xcode CLT (xcode-select --install) | Linker, macOS SDK |
| Windows | Visual Studio Build Tools (C++ workload) | MSVC linker |
Optional — cross-vendor tests
# Linux: Cyclone DDS for live interop tests
sudo apt install cyclonedds-tools # provides ddsperf, ddsls
# macOS via Homebrew
brew install cyclonedds
This enables the crates/discovery/tests/cyclone_live_* cross-vendor tests; without it they are skipped.
Editor setup
- VS Code: the
rust-analyzerextension. In the workspace it works out of the box (90+ crates index in ~30 s on first open). - JetBrains: RustRover or IntelliJ + the Rust plugin.
- Vim/Neovim:
rust-analyzervia an LSP client (coc.nvim, nvim-lspconfig). - Format on save:
rustfmtwith the workspace default (rustfmt.tomlat the root).
Runtime config — what devs really tweak
Install isn't just the build — most problems arise at runtime configuration. What are the important knobs?
Domain ID
All participants in the same domain talk to each other; everything else is invisible. The default 0 is fine for dev — in production use a dedicated ID per tenant/stage:
let participant = factory.create_participant(42, DomainParticipantQos::default())?;
Port mapping follows DDSI-RTPS §9.6.1.4: port = 7400 + 250 * domain_id. The maximum domain ID is 232 (otherwise >65535 port).
Discovery multicast
SPDP uses multicast 239.255.0.1 by default. Works on a LAN out of the box. Problems: container networks (the Docker bridge blocks multicast), cross-subnet (router config needed), cloud VPC (no multicast).
If multicast doesn't work: a TCP backend + static peers (see Transport Tuning recipe 2).
Fast discovery for dev loops
The default discovery heartbeat is 1 s. Too slow for dev loops (run, write, exit, run). Fast mode:
use zerodds_dcps::runtime::RuntimeConfig;
let cfg = RuntimeConfig {
tick_period: Duration::from_millis(20),
spdp_period: Duration::from_millis(100),
..RuntimeConfig::default()
};
let participant = factory.create_participant_with_config(0, DomainParticipantQos::default(), cfg)?;
▶ Runnable example: rust-dev-install-runtimeconfig
That brings match latency under 200 ms. Not for production — 10× more discovery traffic.
Logging
ZeroDDS uses tracing. In dev:
# Cargo.toml
tracing-subscriber = "0.3"
# main.rs
fn main() {
tracing_subscriber::fmt().with_max_level(tracing::Level::DEBUG).init();
// ... rest
}
# CLI
RUST_LOG=zerodds=debug cargo run
Structured logging with span trees shows the discovery flow, sample path, retransmits.
QoS
Out of the box you get the DDS spec defaults (§2.2.3.14, see the QoS Reference): writer=Reliable, reader=BestEffort, History=KeepLast(1), Durability=Volatile. Because the reader requests BestEffort by default, effective delivery is best-effort — for guaranteed delivery, set the reader explicitly to Reliable. For state topics, add Durability=TransientLocal so late joiners see the last value. Ready-made profiles: QoS Cookbook.
Building from source
For contributing to the stack or local patches.
git clone https://github.com/zero-objects/zero-dds.git
cd zero-dds
cargo build --workspace --release
cargo test --workspace
Expectation:
- First build: 5-10 min on an 8-core, depending on disk.
- Incremental: <1 s per crate.
- Full test suite: ~3-5 min (~5400 tests).
Pre-commit checks (run before every push):
cargo fmt --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo run -p dds-lint -- check crates/
Crates as a path dep for patches:
# Cargo.toml in the consuming project
[patch.crates-io]
zerodds-foundation = { path = "/home/you/zero-dds/crates/foundation" }
zerodds-dcps = { path = "/home/you/zero-dds/crates/dcps" }
Platform support
| Tier | Platform | Status | CI |
|---|---|---|---|
| Tier-1 | Linux x86_64 (Ubuntu 24.04, Debian 12) | ✓ all tests | every PR |
| Tier-1 | Linux aarch64 (Ubuntu 24.04) | ✓ all tests | every PR |
| Tier-2 | macOS aarch64 (≥14.0) | ✓ manually verified | release cycle |
| Tier-2 | Windows x86_64 (≥10) | ✓ manually verified | release cycle |
| Tier-3 | FreeBSD 14, OpenBSD 7.5 | ~ best-effort (community) | — |
| Tier-3 | RTOS/embedded (no_std + alloc) | ~ layer-1 only (foundation/cdr/qos/types) | — |
What next
- Topic type via IDL: typed messages instead of
RawBytes→ theidlccompiler. - Cross-process pub/sub: two
cargo runprocesses on the same domain ID, one machine. - Cross-vendor: a ZeroDDS subscriber against a Cyclone DDS publisher → see Transport Tuning.
- QoS tuning: non-default QoS for late joiners, failover, real-time → QoS Cookbook.
- Enable security:
--features security→ Security Plugin-Chain.