6.7 RTIPC之XDDP实例分析
XDDP 跨域数据报协议,允许线程在 Xenomai 域与 Linux 域之间通过消息管道(Message pipes)通信,且实时任务不会离开 Xenomai 域,不会影响实时性。
XDDP 有如下特性:
- 通信机制 :
- 支持数据报通信,类似于 IDDP;
- 支持流式缓存区通信,类似于 BUFP。
- 内存空间管理 :内存空间的分配实际上在
bind操作中完成,所以应在bind之前申请本地内存池。- 数据报通信机制中,可通过
setsockopt + XDDP_POOLSZ申请本地内存池,不使用 Xenomai 系统内存池。 - 流式缓存通信机制中,必须通过
setsockopt + XDDP_BUFSZ申请缓冲区。
- 数据报通信机制中,可通过
- 端口号:使用数字端口号管理,支持动态端口号分配
- 端口标签化(Labeled Port) :为端口赋予可读名称(如
"iddp-demo"),通过名称连接。
Xenomai 源码 demo/posix/cobalt 目录自带了示例程序,非常完整的演示上述特性。
| 特性 | xddp-echo.c | xddp-stream.c | xddp-label.c |
|---|---|---|---|
| 寻址方式 | 指定端口号 | 指定端口号 | 通过标签动态查找端口 |
| 通信机制 | 数据报 | 流式缓存区 | 数据报 |
| 连接模式 | 无连接 | 无连接 | 无连接 |
| 内存空间 | 单独申请独立内存池 xddp-pool |
本地缓存区 | 使用 Xenomai 系统内存池 system heap (默认) |
6.7.1 XDDP 实时/非实时端口通信:xddp-echo.c
1. 代码概述
本程序演示了Xenomai实时线程与Linux常规线程通过XDDP协议进行双向通信的过程。实时线程通过XDDP套接字发送数据,常规线程通过字符设备文件先读后写,实现数据回显功能。如下图所示,共经历发送、接收、回送、回收共 4 个步骤。

- 头文件包含
代码开始部分包含了多个头文件,用于标准输入输出、线程操作、实时 IPC(进程间通信)、以及一些其他必要的系统功能。其中,<rtdm/ipc.h> 是与 Xenomai 实时数据分发协议相关的头文件。
- 全局变量与常量
c
pthread_t rt, nrt; // 实时线程和常规线程句柄
-
pthread_t rt, nrt;:定义了两个线程变量,用于标识实时线程和常规线程。 -
XDDP_PORT:定义了实时线程端口号,也是常规线程打开设备时使用的次设备号。#define XDDP_PORT 0 // 通信端口号(端口号0对应/dev/rtp0)
- 消息数组
msg[] 数组包含了一系列字符串消息。这些消息将用于演示实时和常规线程之间的通信。
static const char *msg[] = {
"Surfing With The Alien",
"Lords of Karma",
"Banana Mango",
"Psycho Monkey",
"Luminous Flesh Giants",
"Moroccan Sunset",
"Satch Boogie",
"Flying In A Blue Dream",
"Ride",
"Summer Song",
"Speed Of Light",
"Crystal Planet",
"Raspberry Jam Delta-V",
"Champagne?",
"Clouds Race Across The Sky",
"Engines Of Creation"
};
2. main函数流程
- 信号屏蔽:阻塞SIGINT/SIGTERM/SIGHUP信号
- 线程属性配置:
- 实时线程:调度策略设为 SCHED_FIFO 策略,优先级为 42。
- 常规线程,调度策略设为 SCHED_OTHER 策略。
- 线程创建:分别启动实时线程和常规线程
- 信号等待:主线程阻塞等待终止信号
- 资源回收:取消线程并等待退出
3. realtime_thread 实时线程
-
创建XDDP套接字:
csocket(AF_RTIPC, SOCK_DGRAM, IPCPROTO_XDDP) -
配置内存池:
csetsockopt(XDDP_POOLSZ, 16KB) // 专用内存池避免系统资源竞争 -
绑定端口:
cbind(port=0) // 对应/dev/rtp0设备 -
数据收发循环:
csendto()发送预设消息 -> recvfrom()接收回显数据 clock_nanosleep(500ms) // 让渡出部分实际给其它任务
4. regular_thread 常规线程
-
打开字符设备:
copen("/dev/rtp0", O_RDWR) -
数据回显循环:
cread()接收实时数据 -> write()原样回写
6. 运行及输出
程序输出示例:
./xddp-echo
realtime_thread: sent 22 bytes, "Surfing With The Alien"
=> "Surfing With The Alien" echoed by peer
realtime_thread: sent 14 bytes, "Lords of Karma"
=> "Lords of Karma" echoed by peer
realtime_thread: sent 12 bytes, "Banana Mango"
=> "Banana Mango" echoed by peer
......
观察内存池,其独立申请了 xddp-pool@0 内存池,没有使用 system heap。
# cat /proc/xenomai/heap
TOTAL FREE NAME
4194304 4183872 system heap
16384 16384 debug log
262144 261968 shared heap
262144 262112 private heap[314]
16384 16384 xddp-pool@0
6.7.2 xddp-stream.c XDDP流式传输示例分析
1. 代码概述
XDDP 除了发送数据报文外,还可以通过端口以字节流模式传输数据。当需要向Linux域发送的数据无需保持消息边界时,这种模式能有效提升带宽利用率并降低传输开销。
当使用 setsockopt + XDDP_BUFSZ 为套接字设置非零缓冲区大小时将启用此功能。任何发送函数中传递 MSG_MORE 标志,数据会持续累积至流缓冲区,直到在满足以下任一条件:
- Linux域接收端被唤醒并开始消费数据(
xddp-stream.c演示的场景) - 不同源端口尝试向同一目标端口发送数据
- 发送标志中未包含
MSG_MORE
xddp-stream.c 开启了 XDDP 流式传输功能,通过 MSG_MORE 标志实现消息分片聚合传输,展示了大数据量传输场景下的优化方法。实时线程使用分散写入方式发送消息,常规线程先读后写,实现数据回显功能。如下图所示,共经历发送、接收、回送、回收共 4 个步骤。

2. 与 xddp-echo.c 相比的变化点
与 xddp-echo.c 相比,只有 realtime_thread 实时线程发生了变化:
-
流式缓冲区配置:
csetsockopt(XDDP_BUFSZ=1024) // 设置1KB流式缓冲区 -
分片发送机制:
cfor(b=0; b<len; b++) { sendto(msg[n]+b, 1, MSG_MORE) // 分片发送单字节 }
3. 运行及输出
./xddp-stream
realtime_thread: sent (scattered) 22-bytes message, "Surfing With The Alien"
=> "Surfing With The Alien" echoed by peer
realtime_thread: sent (scattered) 14-bytes message, "Lords of Karma"
=> "Lords of Karma" echoed by peer
realtime_thread: sent (scattered) 12-bytes message, "Banana Mango"
=> "Banana Mango" echoed by peer
......
6.7.3 xddp-label.c XDDP标签化通信示例分析
1. 代码概述
本示例引入端口标签机制,演示了Xenomai实时线程与Linux常规线程通过XDDP协议进行双向通信的过程。系统包含两个实时线程(收发分离)和一个常规线程(消息环回),形成双向通信环路。如下图所示,共经历发送、接收、回送、回收共 4 个步骤。

2. 与 xddp-echo.c 相比的变化点
- 新增标签定义
c
#define XDDP_PORT_LABEL "xddp-demo" // 语义化端口标识
- 单个实时线程拆分成两个实时线程
-
realtime_thread1:- 创建标签化监听端口
- setsockopt(XDDP_LABEL): 内核注册标签
- bind(sipc_port=-1): 自动分配物理端口
- 持续接收常规线程转发的数据
- 创建标签化监听端口
-
realtime_thread2:- 动态发现标签端口
- connect(XDDP_LABEL): 连接标签
- getpeername(): 获取实际端口号
- 定时发送测试消息
- 动态发现标签端口
regular_thread:- 通过/proc接口访问标签端口:
/proc/xenomai/registry/rtipc/xddp/xddp-demo - 从 realtime_thread2 接收,转发到 realtime_thread1,实现消息环回。
- 通过/proc接口访问标签端口:
3. 运行及输出
当 realtime_thread2 连接到 realtime_thread1 创建的标签化端口时,才会开始发送。并且在发送之前,打印出标签实际对应的动态分配的端口号。
注意,实际在常规线程中打开的是 /proc/xenomai/registry/rtipc/xddp/xddp-demo,并不是 /dev/rtp0。
./xddp-label
realtime_thread2: NRT peer is reading from /dev/rtp0
realtime_thread2: sent 22 bytes, "Surfing With The Alien"
realtime_thread1: "Surfing With The Alien" relayed by peer
realtime_thread2: sent 14 bytes, "Lords of Karma"
realtime_thread1: "Lords of Karma" relayed by peer
realtime_thread2: sent 12 bytes, "Banana Mango"
realtime_thread1: "Banana Mango" relayed by peer
......