Frequently Asked Questions
The 30 questions developers ask most often when adopting Astute DDS, ordered by frequency. Answers describe Astute DDS behaviour only.
Contents
- What is Astute DDS?
- How do I publish and subscribe to a topic?
- What is the difference between
read()andtake()? - Why don't late-joining subscribers receive earlier samples?
- What does the
RELIABILITYQoS do? - What does the
DURABILITYQoS do? - What is the difference between
HISTORYandDURABILITY? - How do I specify a domain ID?
- Why aren't my publisher and subscriber discovering each other?
- What IDL features are supported?
- How do I filter samples I published myself?
- What characters are allowed in topic names?
- How do I detect when a remote writer or reader goes away?
- How do I receive a callback when new data arrives?
- What does "Incompatible QoS" mean?
- How do I send samples larger than a UDP datagram?
- How do I configure which network interface is used?
- Can I use Astute DDS on a network without multicast?
- How do I tune for low latency?
- Why do I see latency spikes when publishing large samples?
- How do I bridge two DDS domains?
- What language bindings are available?
- Which platforms and OS versions are supported?
- How do I enable DDS Security?
- How do I persist data across restarts?
- How do I record and replay traffic?
- How do I evolve a data type without breaking subscribers?
- How do I use content-filtered topics?
- How do I configure QoS from an XML file?
- How do I debug interop or discovery issues?
1. What is Astute DDS?
Astute DDS is a C++20 implementation of the OMG Data Distribution Service
(DDS) DCPS API, DDSI-RTPS 2.5 wire protocol, DDS-XTypes 1.3 type system,
DDS-Security 1.1/1.2 plugins, and IDL 4.2. It is delivered as the static
library libastutedds.a (plus C, Python and Rust bindings) and ships with
the astutedds-inspect diagnostics GUI and an interoperable Shapes Demo.
2. How do I publish and subscribe to a topic?
Create a DomainParticipant, a Topic, then a DataWriter (publisher side)
or DataReader (subscriber side):
using namespace astutedds::dcps;
auto dpf = DomainParticipantFactory::get_instance();
auto dp = dpf->create_participant(0, PARTICIPANT_QOS_DEFAULT, nullptr, 0);
auto topic = dp->create_topic("Hello", "HelloMsg", TOPIC_QOS_DEFAULT, nullptr, 0);
// Publisher
auto pub = dp->create_publisher(PUBLISHER_QOS_DEFAULT, nullptr, 0);
auto writer = pub->create_datawriter(topic, DATAWRITER_QOS_DEFAULT, nullptr, 0);
writer->write(sample, HANDLE_NIL);
// Subscriber
auto sub = dp->create_subscriber(SUBSCRIBER_QOS_DEFAULT, nullptr, 0);
auto reader = sub->create_datareader(topic, DATAREADER_QOS_DEFAULT, nullptr, 0);
See Getting Started › First Application.
3. What is the difference between read() and take()?
read()returns samples but leaves them in the reader cache, so later calls (or other readers in the same subscriber) can read them again.take()returns samples and removes them from the cache.
Use read() when the topic represents shared state you want to inspect
repeatedly; use take() when the topic represents events you want to
consume exactly once.
4. Why don't late-joining subscribers receive earlier samples?
By default DURABILITY is VOLATILE, so samples written before a subscriber
is matched are not delivered. To deliver historic samples to late joiners,
configure the writer and matching readers with TRANSIENT_LOCAL
durability (which also requires RELIABLE reliability):
DataWriterQos qos;
writer->get_qos(qos);
qos.durability().kind = TRANSIENT_LOCAL_DURABILITY_QOS;
qos.reliability().kind = RELIABLE_RELIABILITY_QOS;
writer->set_qos(qos);
For persistence across writer restarts use the
Persistence Service or the TRANSIENT/PERSISTENT
durability kinds.
5. What does the RELIABILITY QoS do?
BEST_EFFORT(default for many built-in topics): samples that are lost on the wire are not retransmitted. Lowest overhead.RELIABLE: the writer tracks acknowledgements (ACKNACK/ heartbeat) from each matched reader and retransmits missed sequence numbers until the reader catches up or the history is full.
Reliability is per-writer/per-reader and must be compatible: a BEST_EFFORT
reader can match a RELIABLE writer, but not the reverse.
6. What does the DURABILITY QoS do?
DURABILITY controls whether samples are retained for delivery to readers
that join after the sample was written:
| Kind | Available to late joiners? |
|---|---|
VOLATILE |
No |
TRANSIENT_LOCAL |
Yes, while the writer is alive |
TRANSIENT |
Yes, across writer lifetime (via Persistence Service) |
PERSISTENT |
Yes, across process restarts (on-disk) |
7. What is the difference between HISTORY and DURABILITY?
HISTORY (KEEP_LAST(depth) or KEEP_ALL) controls how many samples the
writer/reader cache holds at any instant. DURABILITY controls whether the
writer offers samples to readers that match later. They work together but
solve different problems: KEEP_ALL alone does not make samples available
to late joiners.
8. How do I specify a domain ID?
Pass the domain ID as the first argument to create_participant:
auto dp = DomainParticipantFactory::get_instance()
->create_participant(42, PARTICIPANT_QOS_DEFAULT, nullptr, 0);
Participants on different domains do not communicate. The DDSI-RTPS port
formula 7400 + 250 * domain_id determines the base UDP ports used for
discovery.
9. Why aren't my publisher and subscriber discovering each other?
Common causes:
- Different domain IDs — both participants must use the same ID.
- Multicast blocked — SPDP uses UDP multicast on
239.255.0.1by default. Check the host firewall and switch IGMP snooping. - Wrong network interface — on multi-homed hosts set
ASTUTEDDS_NETWORK_INTERFACE=<name>or configure it in the discovery JSON / XML profile (see JSON Discovery Config). - Incompatible QoS — see question 15.
- Different transports — verify both peers use UDPv4 (or both UDPv6, TCP, SHM).
Enable trace logging with ASTUTEDDS_LOG_LEVEL=trace and inspect a packet
capture with astutedds-inspect.
10. What IDL features are supported?
The bundled astutedds-idl compiler implements OMG IDL 4.2 including:
- Primitive types (
boolean,octet, integer typesint8–uint64,float/double/long double,char/wchar,string/wstring). - Structures, unions, enumerations, bitmasks, typedefs.
- Bounded and unbounded sequences, arrays, maps.
@key,@id,@optional,@default,@range,@min,@max,@unit,@extensibility(FINAL|APPENDABLE|MUTABLE),@nested.- Constants and
modulenamespaces.
Generated C++ uses XCDR2 by default with optional XCDR1 for interop.
11. How do I filter samples I published myself?
Two options:
- Ignore at participant level: call
dp->ignore_publication(handle)passing the local writer'sInstanceHandle_t. - Filter in the reader callback using
SampleInfo::publication_handleand comparing it to your writer'sget_instance_handle().
A content-filtered topic can also exclude a self-published key field.
12. What characters are allowed in topic names?
Topic names may contain ASCII alphanumeric characters, _, and / as a
hierarchy separator. Length is bounded by 256 characters. Avoid leading
digits and reserved DDS built-in prefixes (DCPS, dds). Type names follow
the same rule.
13. How do I detect when a remote writer or reader goes away?
Install a DataReaderListener and implement on_subscription_matched /
on_liveliness_changed, or poll
reader->get_subscription_matched_status(). The current_count_change
field is negative when a peer un-matches.
Liveliness is governed by the LIVELINESS QoS — set
kind = AUTOMATIC_LIVELINESS_QOS with a lease_duration to detect
silent peers within a bounded time.
14. How do I receive a callback when new data arrives?
Attach a listener with the DATA_AVAILABLE_STATUS mask:
class MyListener : public DataReaderListener {
void on_data_available(DataReader* reader) override {
// call reader->take(...) here
}
};
reader->set_listener(&listener, DATA_AVAILABLE_STATUS);
on_data_available fires for both new samples and instance-lifecycle
changes; always inspect SampleInfo::valid_data before dereferencing the
sample payload.
15. What does "Incompatible QoS" mean?
A writer and reader match only when every Request/Offered QoS is compatible:
| Policy | Requested ≤ Offered |
|---|---|
RELIABILITY |
reader BEST_EFFORT ≤ writer RELIABLE |
DURABILITY |
reader kind ≤ writer kind (in spec ordering) |
DEADLINE |
reader period ≥ writer period |
LATENCY_BUDGET |
reader duration ≥ writer duration |
OWNERSHIP |
must be equal (SHARED or EXCLUSIVE) |
PARTITION |
at least one partition name must overlap |
Listen for on_offered_incompatible_qos / on_requested_incompatible_qos
to find the exact policy ID at runtime.
16. How do I send samples larger than a UDP datagram?
Astute DDS automatically fragments samples larger than the configured
fragment_size (default 1344 bytes for IPv4) and reassembles them on the
reader using DDSI-RTPS DATA_FRAG submessages. The reliability protocol
recovers missing fragments without re-sending the whole sample.
For very large samples (≥ 1 MB) increase the OS socket buffers:
sudo sysctl -w net.core.rmem_max=8388608
sudo sysctl -w net.core.wmem_max=8388608
and consider switching to the shared-memory transport for local readers.
17. How do I configure which network interface is used?
Three options, in order of precedence:
- Environment variable:
ASTUTEDDS_NETWORK_INTERFACE=eth0. - JSON discovery config — see JSON Discovery Config.
- XML QoS profile — see DDS-XML QoS Profiles.
If none is set Astute DDS selects the first non-loopback interface with a multicast-capable address.
18. Can I use Astute DDS on a network without multicast?
Yes. Two alternatives:
- Unicast SPDP peer list: provide a list of peer host/port pairs in the discovery config; Astute DDS unicasts SPDP announcements to each peer.
- TCP transport: switch the participant to the TCP RTPS transport for environments that block UDP entirely. See DDS Domain Router for crossing isolated networks.
19. How do I tune for low latency?
- Use
RELIABLEreliability withKEEP_LAST(1)history on both ends so retransmits are minimal. - Enable the shared-memory transport for co-located participants.
- Pin Astute DDS threads with CPU affinity and use real-time scheduling
(
SCHED_FIFO) on the publisher and subscriber processes. - Disable Nagle by using UDP (the default).
- Increase socket buffers (see question 16) to absorb bursts.
- Set
LATENCY_BUDGET = 0to disable any batching delay.
20. Why do I see latency spikes when publishing large samples?
When samples exceed the OS default socket buffer (often 208 KB on Linux),
the kernel drops packets and the reliable protocol must retransmit, causing
spikes. Raising net.core.rmem_max / net.core.wmem_max to at least the
sample size resolves this. Consider fragmenting with smaller fragment_size
on lossy networks.
21. How do I bridge two DDS domains?
Use the Astute DDS Domain Router — a service that joins two or more domains and forwards configured topics between them, with optional key/content filtering and QoS translation. See DDS Domain Router.
22. What language bindings are available?
| Language | Status | Notes |
|---|---|---|
| C++20 | Stable | Primary API — libastutedds.a |
| C | Stable | Flat C API for FFI, see include/astutedds/c/astutedds.h |
| Python | Stable | pybind11 bindings, CPython 3.10 – 3.13 |
| Rust | Beta | astutedds crate (safe wrapper over the C API) |
23. Which platforms and OS versions are supported?
| Platform | Tested versions |
|---|---|
| Linux | Ubuntu 22.04 / 24.04, RHEL 9 / 10, AlmaLinux 9 / 10, Debian 12 |
| Windows | Windows 10, Windows 11, Windows Server 2022 |
The Linux Python wheels are tagged manylinux_2_28 (glibc ≥ 2.28) and run
on any compatible distribution.
24. How do I enable DDS Security?
- Provision identity (X.509) and permissions (signed XML) artefacts.
- Configure the participant property QoS with the Auth, Access Control and Crypto plugin properties (CA cert, identity cert/key, permissions file, governance file).
- Link against Astute DDS built with
-DASTUTEDDS_ENABLE_SECURITY=ON.
See DDS Security for end-to-end instructions and a governance/permissions template.
25. How do I persist data across restarts?
Run the Persistence Service alongside your domain. It subscribes to
configured TRANSIENT / PERSISTENT topics, stores samples in a local
database (SQLite by default), and re-publishes them to late-joining
subscribers — including those that join after the original writer is gone.
See Persistence Service.
26. How do I record and replay traffic?
Use the bundled astutedds-record tool to capture a domain into a
.astdb file, and astutedds-replay to publish it back with adjustable
time scaling. Recording is type-aware and uses XCDR2 internally. See
Recording and Replay.
27. How do I evolve a data type without breaking subscribers?
Annotate the IDL type with @extensibility(MUTABLE) (or APPENDABLE) and
tag each member with @id(N). XCDR2 mutable streams allow:
- Adding new members to either end.
- Removing optional members.
- Reordering members.
Mismatched members are skipped via the X-Types assignability rules.
@extensibility(FINAL) locks the layout and must be used when binary
compatibility with legacy XCDR1 readers matters.
28. How do I use content-filtered topics?
Create a ContentFilteredTopic from a regular topic with a SQL-like filter
expression and bind a DataReader to it:
std::vector<std::string> params{"42"};
auto cft = dp->create_contentfilteredtopic(
"HighSeverity", topic, "severity > %0", params);
auto reader = sub->create_datareader(cft, DATAREADER_QOS_DEFAULT, nullptr, 0);
The filter is evaluated on the writer side when possible to save bandwidth.
29. How do I configure QoS from an XML file?
Use XmlQosLoader to read a DDS-XML profile and apply it when creating
entities:
XmlQosLoader loader;
loader.load_file("qos_profiles.xml");
auto qos = loader.get_datawriter_qos("MyLib", "ReliableProfile");
auto writer = pub->create_datawriter(topic, qos, nullptr, 0);
See DDS-XML QoS Profiles for the schema and worked examples.
30. How do I debug interop or discovery issues?
- Run
astutedds-inspectagainst the domain to view discovered participants, endpoints and matched status in real time. - Capture traffic with
tcpdump -i any -w dds.pcap 'udp port 7400 or portrange 7400-7500'and open it in Wireshark — the RTPS dissector decodes SPDP, SEDP and user data. - Enable trace logs:
ASTUTEDDS_LOG_LEVEL=trace ASTUTEDDS_LOG_FILE=/tmp/astutedds.log. - Verify entity IDs and ports:
- SPDP writer/reader:
00:01:00:c2/00:01:00:c7 - SEDP publication:
00:00:03:c2/00:00:03:c7 - SEDP subscription:
00:00:04:c2/00:00:04:c7 - Base port:
7400 + 250 × domain_id.
- SPDP writer/reader:
- Confirm both peers advertise compatible vendor IDs and protocol version (DDSI-RTPS 2.5).