|
VLink
2.0.0
A high-performance communication middleware
|
本章覆盖 VLink 在语言、框架、部署三处边界的对外接口。三者均在不改动业务通信代码的前提下把 VLink 接入更大的系统,并保持 URL 通信契约(见 概述)的不变量:通信端点是 URL,承载是字节,行为可由配置外置。它们按"开发期编码 → 链接期装配 → 运行期注入"的时间顺序级联,构成从源码到现场的完整集成面。
| 集成面 | 章节 | 边界 | 作用 |
|---|---|---|---|
| C API | 13.1–13.8 | 语言 | 以稳定 C ABI 投影六原语数据面,使 C / Python / Go / Rust 等无法实例化 C++ 模板的语言接入 VLink |
| 扩展开发 | 13.9–13.17 | 框架 | 以稳定接口与插件机制开放扩展点:URL 重映射、动态类型、功能组件、子系统后端替换 |
| 环境变量 | 13.18–13.27 | 部署 | 运行时配置的最低优先级来源,使后端绑定、日志、诊断在不重编不改源码下按部署环境注入 |

VLink C API 以稳定的 C ABI 暴露六个通信原语的数据面,适用于跨语言互操作、要求 ABI 跨版本稳定、或运行环境不具备 C++ 运行时的场景。它不替代 C++ API,而是其数据面的等价投影——URL 语义、通信模型语义、传输后端清单与 C++ 完全一致。
C ABI 无法承载 C++ 模板与异常,因此 C API 对核心能力做了四点收敛。理解这四点即可解释后续全部接口的形态与约束。
| 机制 | 规则 | 工程含义 |
|---|---|---|
| 统一载荷 | 所有消息以 data + size 字节缓冲区进出,对应 C++ 侧的 vlink::Bytes | 序列化/反序列化由调用方负责;C API 不感知消息结构 |
| 句柄模式 | 每个原语对应一个不透明句柄结构体,create 分配、destroy 释放,成对调用 | 句柄即资源所有权凭证;native_handle 外的字段为内部保留,禁止读写 |
| 统一返回码 | 所有报错函数返回 vlink_ret_t,仅 0(VLINK_RET_NO_ERROR)为成功 | 异常被转换为返回码;调用方必须逐次检查符号常量,不可把所有非负值视作成功 |
| 序列化声明 | 创建接口接收 vlink_schema_info_t,声明字节如何被解读 | 供发现、代理、录制、可视化识别话题类型;不参与编解码本身 |
覆盖范围。 C API 覆盖六原语数据面(创建/销毁、发布/订阅、请求/响应、读写字段),并扩展支持消息级安全加密与传输层 TLS。它不覆盖 QoS、Bag 录制与服务发现,这些能力仍需 C++ API。url 参数格式(<scheme>://<topic>)与切换后端的语义同 C++:模型语义见 通信模型,后端清单见 传输后端与 URL。

C API 由构建开关 ENABLE_C_API 控制,编译为独立库,导出链接别名 vlink::c_api:
头文件为纯 C 头(extern "C" 保护,C 与 C++ 均可包含):
回调中的 data 仅在回调执行期间有效,需外带时必须在回调内拷贝。可运行示例见 examples/c_api/c_pubsub(演示 Event 模型的发布/订阅全流程);RPC、Field、安全等其余原语的用法参照本章接口说明与 13.5–13.6,整体说明见 快速开始。
返回码将 C++ 侧的异常与状态转换为整数;调用方据其区分"可重试的状态"与"编程错误"。
| 返回码 | 值 | 含义与处理 |
|---|---|---|
VLINK_RET_NO_ERROR | 0 | 成功 |
VLINK_RET_UNEXPECTED_ERROR | 1 | 条件尚未满足(如暂无订阅者);稍后重试 |
VLINK_RET_INVALID_ERROR | 2 | 空指针、参数非法或句柄无效;属调用方编程错误 |
VLINK_RET_MEMORY_ERROR | 3 | 分配失败或输出缓冲区容量不足(见 vlink_get);扩容后重试 |
VLINK_RET_RUNTIME_ERROR | 4 | 运行期状态错误或构造异常(如在请求回调外调用 vlink_reply) |
VLINK_RET_TRANSFER_ERROR | 5 | 收发失败(无对端、加解密失败);待对端就绪后重试 |
VLINK_RET_UNKNOWN_ERROR | -1 | 未分类内部错误;记录并上报 |
六种句柄一一对应六个原语,均为不透明 POD 结构体。调用方仅通过 create / destroy 管理其生命周期,不得读写结构体内部字段。
| 句柄类型 | 对应原语 | 通信模型 |
|---|---|---|
vlink_publisher_handle_t | Publisher | Event 发布 |
vlink_subscriber_handle_t | Subscriber | Event 订阅 |
vlink_server_handle_t | Server | Method 服务端 |
vlink_client_handle_t | Client | Method 客户端 |
vlink_setter_handle_t | Setter | Field 写入 |
vlink_getter_handle_t | Getter | Field 读取 |
回调均在 VLink 内部线程触发,data 指针仅在回调期内有效。回调体应短小、非阻塞,并避免在其中调用其它 VLink API(见 13.8.1)。
| 回调类型 | 签名 | 触发时机 |
|---|---|---|
vlink_connect_callback_t | void (*)(bool is_connected, void* user_data) | Publisher / Client 连接状态变化 |
vlink_msg_callback_t | void (*)(const uint8_t* data, size_t size, void* user_data) | Subscriber 收到消息 / Getter 推送更新 |
vlink_req_callback_t | void (*)(const uint8_t* data, size_t size, void* user_data) | Server 收到请求 |
vlink_resp_callback_t | void (*)(const uint8_t* data, size_t size, void* user_data) | Client 收到响应 |
vlink_schema_info_t 在创建节点时声明该话题字节的序列化语义,供发现、代理、录制与可视化识别类型;它不参与编解码本身。
约束:
ser 与 schema 须同时提供或同时省略;只填一侧返回 VLINK_RET_INVALID_ERROR。schema_info == NULL,或 ser 为空且 schema == VLINK_SCHEMA_UNKNOWN,等价于不显式声明。序列化类型族与编解码机制见 消息序列化。
下列接口覆盖三种通信模型的数据面,是绝大多数集成所需的全部入口。带安全/TLS 的变体见 13.6。
| 函数 | 语义 |
|---|---|
vlink_create_publisher(url, schema, handle) | 创建并初始化 Publisher |
vlink_destroy_publisher(handle) | 销毁并释放资源 |
vlink_publish(handle, data, size) | 发布消息;无订阅者返回 TRANSFER_ERROR |
vlink_publish_by_force(handle, data, size) | 强制发布,跳过订阅者在线检查;适合 late-join |
vlink_wait_for_subscribers(handle, timeout_ms) | 阻塞至有订阅者或超时 |
vlink_has_subscribers(handle) | 非阻塞查询是否有订阅者 |
vlink_detect_subscribers(handle, cb, user_data) | 注册连接状态变化回调 |
vlink_create_subscriber(url, schema, handle, msg_cb, user_data) | 创建 Subscriber 并注册收消息回调;msg_cb 不可为 NULL |
vlink_destroy_subscriber(handle) | 销毁并释放资源 |
| 函数 | 语义 |
|---|---|
vlink_create_server(url, schema, handle, req_cb, user_data) | 创建 Server 并注册请求回调 |
vlink_destroy_server(handle) | 销毁并释放资源,含请求/响应协调状态 |
vlink_reply(handle, data, size) | 在请求回调内提供响应;回调外调用返回 RUNTIME_ERROR |
vlink_create_client(url, schema, handle) | 创建 Client |
vlink_destroy_client(handle) | 销毁并释放资源 |
vlink_invoke(handle, data, size, resp_cb, user_data) | 发请求并注册响应回调;不需响应时 resp_cb 传 NULL |
vlink_wait_for_server(handle, timeout_ms) | 阻塞至 Server 可用或超时 |
vlink_has_server(handle) | 非阻塞查询是否已连接 Server |
vlink_detect_server(handle, cb, user_data) | 注册连接状态变化回调 |
| 函数 | 语义 |
|---|---|
vlink_create_setter(url, schema, handle) | 创建 Setter |
vlink_destroy_setter(handle) | 销毁并释放资源 |
vlink_set(handle, data, size) | 写入最新字段值并广播 |
vlink_create_getter(url, schema, handle, msg_cb, user_data) | 创建 Getter;msg_cb 为 NULL 走轮询、非 NULL 走推送 |
vlink_destroy_getter(handle) | 销毁并释放资源 |
vlink_get(handle, data, size) | 轮询读取最新值至调用方缓冲区 |
发送类函数(vlink_publish / vlink_publish_by_force / vlink_invoke / vlink_set)对 data 做浅拷贝:缓冲区只需在函数返回前有效,返回后即可复用或释放。回调入参 data 仅回调期内有效,需外带时在回调内拷贝至自有缓冲区,切勿保存裸指针。
vlink_reply 必须在 vlink_req_callback_t 内调用。请求处理流程如下:
vlink_reply(handle, data, size) 提供非空响应;回调返回后该响应被发往客户端。vlink_reply 或传 size == 0,请求以空响应完成。vlink_reply 返回 VLINK_RET_RUNTIME_ERROR,因为已无进行中的请求。惯例是将 Server 句柄自身作为 user_data 传入,便于在回调内取得句柄:
创建 Getter 时 msg_callback 的取值决定工作模式:传非 NULL 走推送模式,每次值更新触发回调;传 NULL 走轮询模式,由调用方用 vlink_get 主动读取最新值。
vlink_get 的 *size 是双向参数:入参为缓冲区容量,出参为实际数据大小。容量不足时返回 VLINK_RET_MEMORY_ERROR 并把所需大小写回 *size(data 不被修改),调用方据此扩容重试;尚无可用值时返回 VLINK_RET_TRANSFER_ERROR。
C API 提供两层正交的加密能力:消息级 AEAD 加密(应用层,端到端)与传输层 TLS(信道级,逐跳)。二者相互独立,可单独或叠加使用。

启用消息加密的节点必须用 vlink_create_secure_*() 系列创建——加密在节点初始化时一次性装配,没有运行期开关。配置经 vlink_security_config_t 传入,推荐先用 vlink_security_config_init() 取默认值(PBKDF2 迭代 200000,重放窗口置 4096 即启用重放保护),再按需覆盖字段:
六个原语均有对应的 secure 创建函数,签名与普通版一致、末尾增加一个 const vlink_security_config_t*:
| 函数 | 适用 |
|---|---|
vlink_create_secure_publisher / vlink_create_secure_subscriber | Event 加密收发 |
vlink_create_secure_server / vlink_create_secure_client | Method 加密请求/响应 |
vlink_create_secure_setter / vlink_create_secure_getter | Field 加密读写 |
vlink_security_config_t 支持三种密钥模式,由填入的字段决定:对称(key 或 passphrase + pbkdf2_salt)、RSA 混合(public_key_pem / private_key_pem)、自定义回调(encrypt_callback / decrypt_callback,二者同时安装时覆盖内置路径)。低频选项(AAD 绑定、重放窗口、RSA-PSS 签名密钥)置于 advanced 子结构。各算法语义与字段含义见 安全加密。
不绑定节点、仅需直接加解密缓冲区时,使用独立 Security 句柄:
vlink_security_decrypt 用法对称。输出缓冲区由 C API 分配、由调用方经 vlink_security_free_buffer 释放;空输入返回 VLINK_RET_INVALID_ERROR;认证失败(密文被篡改、密钥错误、签名无效或重放)返回 VLINK_RET_TRANSFER_ERROR。
需要信道级 TLS(当前支持 mqtt://、dds://、ddsc://、ddsr://、zenoh://;someip:// 不消费 ssl.* 配置)时,用 *_with_ssl_options 系列创建。配置先经 vlink_ssl_options_init() 取默认值(verify_peer 默认为 1):
六个原语均有 vlink_create_<role>_with_ssl_options;同时需要消息加密与 TLS 时使用 vlink_create_secure_<role>_with_ssl_options。这些接口会把配置写入节点属性,只有支持 TLS 的后端会据此建立 TLS 通道。vlink_ssl_options_t 字段:verify_peer(非零校验对端证书)、ca_file / cert_file / key_file / key_password、server_name(SNI)、ciphers。TLS 必须在传输连接建立前装配,因此应通过上述创建函数注入;句柄级 vlink_<role>_set_ssl_options 针对已初始化句柄返回 VLINK_RET_RUNTIME_ERROR。
任何支持 C FFI 的语言均可调用 C API。下面给出三种语言的核心片段,要点是声明与 vlink_schema_info_t、句柄结构体匹配的 ABI 布局,并正确管理生命周期。
vlink 为 Python 提供两条路径,**首选原生绑定**:
**原生 nanobind 绑定(首选)**:源码位于 python_api/(vlink_python.cc + vlink.py),编译产出名为 _vlink_nanobind 的扩展模块,由 vlink.py 再导出(from _vlink_nanobind import *)。它是一等公民的面向对象 API,无需手写 ABI 声明,并自动管理生命周期。需在配置时开启构建开关 ENABLE_PYTHON_API(CMakeLists.txt 中默认 OFF),即 cmake -DENABLE_PYTHON_API=ON ...;该开关依赖系统已安装 nanobind。导出的完整类/接口清单(以 python_api/vlink.py 的 __all__ 为准)包括:
Publisher、Subscriber、Server、Client、Setter、Getter、FireForgetServer、FireForgetClient;Security、SecurityConfig、SecurityConfigAdvanced、SecurityPublisher、SecuritySubscriber、SecurityServer、SecurityClient、SecuritySetter、SecurityGetter、SecurityFireForgetServer、SecurityFireForgetClient、SslOptions;BagWriter、BagReader、DiscoveryViewer;Qos、QosProfile、UrlRemap、Logger(含 log_trace/log_debug/log_info/log_warn/log_error/log_fatal)、Status;Bytes、Frame、Uuid、Version、SchemaData、SampleLostInfo、ElapsedTimer、DeadlineTimer、Timer、WheelTimer、MessageLoop、MultiLoop、ThreadPool、SpinLock、CpuProfiler、CpuProfilerGuard、MemoryPool、Process、utils、helpers、quantize;ImplType、TransportType、InitType、SecurityType、ActionType、SchemaType、LogLevel、StatusType 等。具体方法签名以源码 python_api/vlink_python.cc 为准,示例可参考 python_api/examples/。
ctypes 调用 C API 共享库,无需额外构建步骤,但需手写与 vlink_schema_info_t、句柄结构体匹配的 ABI 布局并自行管理生命周期:| 操作 | 线程安全性 |
|---|---|
同一句柄的 create / destroy | 不安全,不可并发 |
同一 Publisher 并发 vlink_publish | 安全 |
| 不同句柄之间并发操作 | 安全,各自独立 |
vlink_reply 在请求回调外调用 | 返回 VLINK_RET_RUNTIME_ERROR |
| 回调内调用其它 VLink API | 视传输层而定,通常不安全;建议改用队列转发后处理 |
create 与 destroy 必须成对;遗漏 destroy 将泄漏内存与传输资源。vlink_get 的缓冲区由调用方分配并管理,*size 入参必须是真实容量。vlink_security_free_buffer 释放,不可用其它释放器。VLink 在不修改框架本体的前提下,以稳定接口与插件机制向应用开放扩展点。本节先建立扩展机制的分类模型,再依使用频度给出接口与最小示例;框架内部使用的扩展接口仅作索引,指向对应专文。

VLink 的扩展点按调用主体分为两类,决定其在文档中的展开深度。
两类扩展在实现形态上又分为**值类型**(UrlRemap、DynamicData,直接实例化使用)与**插件接口**(继承抽象接口、编译为共享库、经 Plugin 动态加载)。
| 扩展 | 头文件 | 用途 | 类别 |
|---|---|---|---|
UrlRemap | extension/url_remap.h | 运行时按 JSON 表重映射 URL,免重编切换后端 | 应用向·值类型 |
DynamicData | extension/dynamic_data.h | 传输编译期未知类型的消息(类型擦除) | 应用向·值类型 |
Plugin | base/plugin.h | 动态库加载器:类型安全加载、版本校验、生命周期管理 | 应用向·加载器 |
LoggerPluginInterface | base/logger_plugin_interface.h | 将日志输出接入第三方框架 | 应用向·插件 |
RunablePluginInterface | extension/runnable_plugin_interface.h | 携带自身事件循环的自包含可运行组件 | 应用向·插件 |
ConvertPluginInterface | extension/convert_plugin_interface.h | Foxglove / Rerun 可视化消息转换 | 应用向·插件 |
SchemaPluginInterface | extension/schema_plugin_interface.h | Protobuf / FlatBuffers schema 反射注册 | 进阶·插件 |
BagPluginInterface | extension/bag_plugin_interface.h | 录制 / 回放时改写 URL 与帧 | 框架内·插件 |
DiscoveryReporter | extension/discovery_reporter.h | 节点上线 / 下线上报 | 框架内 |
TerminalStream | extension/terminal_stream.h | CLI 工具的带缓冲 stdout | 框架内 |
实现插件接口涉及三个宏:VLINK_PLUGIN_REGISTER(Iface) 在接口与实现类内注入由类型名派生的插件 ID,VLINK_PLUGIN_DECLARE(ImplType, major, minor) 在实现 .cc 中导出构造 / 析构入口并声明版本,VLINK_PLUGIN_EXPORT 为共享库符号可见性修饰符。
URL 即通信契约(见 概述),但契约值在源码中确定后,量产部署仍可能需要改变后端或 topic 名。UrlRemap 从 JSON 文件加载一张「原 URL → 目标 URL」映射表,在运行时替换节点使用的地址,使后端切换退化为修改配置文件而非重新编译。
配置为平坦 JSON 对象,键为原 URL 或其子串,值为目标 URL:
convert() 返回首条「键为输入 URL 子串」的规则对应的值;无匹配则原样返回输入。匹配按文件中的规则顺序进行,故较具体的规则应排在前面,避免被宽泛子串规则提前命中。
| 方法 | 语义 |
|---|---|
bool load(file_path) | 加载 JSON;已加载状态下返回 false,需先 unload |
bool unload() | 卸载并清空规则表 |
bool reload(file_path) | 等价于 unload() 后 load() |
const std::string& convert(url) | 转换 URL;无匹配返回原 URL |
bool is_valid() | 是否已成功加载 |
void set_enable_log(enable) | 启用 / 关闭每次转换的 INFO 日志 |
const std::string& get_error_string() | 加载失败时的错误描述 |
**边界条件**:UrlRemap 非线程安全,load / unload / reload / convert 须在同一线程调用,或由调用方加锁。is_valid() 为 false 时 convert() 返回原 URL,不抛异常。除显式构造 UrlRemap 外,同一映射表亦可经环境变量 VLINK_URL_REMAP 全局注入(见 13.20),无需改动任何代码。
事件 / 方法 / 字段三种模型的消息类型均为编译期模板参数,序列化策略据此推导(见 消息序列化)。当通道两端在编译期无法共享具体类型——例如网关按运行时配置转发任意 topic——需要一种类型擦除的载体。DynamicData 将任意 VLink 兼容消息连同类型名标签打包为字节缓冲,在编译期不感知类型的通道上传输,由接收端按类型名还原。它与 Publisher<DynamicData> / Subscriber<DynamicData> 配合使用。
| 方法 | 语义 |
|---|---|
DynamicData& load(type_name, value) | 将消息连同类型名打包,返回自身以支持链式 publish |
T as<T>() | 还原为具体类型 T 并返回 |
bool convert(T& out) | 还原到出参,成功返回 true |
const std::string_view& get_type() | 返回类型名标签 |
bool is_empty() | 是否为空 |
operator>> / operator<< | 与 Bytes 互转,用于自定义传输或落盘 |
**约束**:类型名标签连同结尾 NUL 须短于 20 字节(即名称至多 18 字符,前 20 字节为内联类型名区);不可嵌套打包另一个 DynamicData,亦不支持 CDR 类型;违规用法在编译期被 static_assert 拦截。
与 Bytes 互转,适用于自定义传输或持久化:
Plugin 封装跨平台动态库加载,提供类型安全的接口查找、版本校验与生命周期管理。它是所有插件接口(日志、可运行、转换等)的统一加载入口。
| 方法 | 语义 |
|---|---|
load<Iface>(lib_name, major, minor) | 加载插件,返回接口 shared_ptr;失败返回 nullptr |
has_loaded<Iface>(lib_name) | 查询是否已加载 |
unload<Iface>(lib_name) | 卸载指定插件 |
clear() | 卸载全部插件 |
版本校验规则:major 须与插件声明一致,插件声明的 minor 须不低于调用方要求,否则加载失败。返回的 shared_ptr 在最后一个引用释放时自动卸载共享库,无需手动管理。
load() 接受插件**基础名**,框架按平台补全前缀与后缀:
| 平台 | 前缀 | 后缀 | 示例(基础名 my_plugin) |
|---|---|---|---|
| Linux | lib | .so | libmy_plugin.so |
| macOS | lib | .dylib | libmy_plugin.dylib |
| Windows | 无 | .dll | my_plugin.dll |
默认搜索顺序:
VLINK_PLUGIN_DIR 列出的目录(逗号或空格分隔,最高优先级)../lib64、../lib、./lib64、./lib/lib64、/libload() 的 dir_name / search_paths 参数可覆盖默认搜索路径。VLINK_PLUGIN_DIR 的运行期定义见 13.20。
各类插件接口的实现遵循同一模板,差异仅在于继承的接口与重写的虚函数:
VLINK_PLUGIN_REGISTER(Iface) 注入插件 ID;VLINK_PLUGIN_REGISTER;.cc 末尾以 VLINK_PLUGIN_DECLARE(ImplType, major, minor) 导出入口;SHARED 库;Plugin::load<Iface>() 加载。以一个自定义监控插件为例。
monitor_plugin.h(接口)
prometheus_monitor.cc(实现与导出)
CMakeLists.txt
宿主加载
实现 LoggerPluginInterface 可将 VLink 日志转发至任意第三方框架(spdlog、log4cxx、自定义滚动日志等)。接口仅含两个纯虚函数。
| 方法 | 语义 |
|---|---|
bool init(app_name) | 初始化后端 |
bool log(int level, str) | 输出一条日志,level 为级别整数 |
level 与 Logger::Level 的对照:0 Trace、1 Debug、2 Info、3 Warn、4 Error、5 Fatal。
加载后即接管全局日志输出(日志后端总览见 基础库),亦可经环境变量 VLINK_LOG_PLUGIN 注入(见 13.21):
RunablePluginInterface(类名拼写 Runable 为源码约定,单 n)继承自 MessageLoop,使插件携带自身事件循环线程,成为可独立持有订阅、定时器、状态机的自包含组件。实现需重写两个生命周期钩子。
| 方法 | 调用时机 |
|---|---|
on_init() | async_run() 成功后调用,在此创建订阅、定时器等运行期资源 |
on_deinit() | 卸载前调用,释放 on_init() 创建的全部资源 |
实现
加载与运行
Proxy 加载可运行插件的场景见 可观测性。
ConvertPluginInterface 供 vlink-foxglove 与 vlink-rerun 桥接器使用,将 VLink 的序列化字节流转换为目标可视化后端能解析的格式。接口不依赖任何第三方库,便于外部独立实现。
| 目标 | payload 格式 | type_name 含义 |
|---|---|---|
Target::kFoxglove | FlatBuffer / Protobuf 二进制 | Foxglove schema 名 |
Target::kRerun | UTF-8 JSON(描述 Rerun archetype) | Rerun archetype 名 |
核心虚函数:
| 方法 | 语义 |
|---|---|
init(config) | 加载后调用,返回 false 则卸载 |
can_convert(ser_type, target) | 是否处理某序列化类型与目标的组合 |
get_schema(ser_type, target, info) | 注册通道时返回 schema 元数据 |
convert(ser_type, raw, target, payload) | 将每条消息的 raw 转为目标格式 |
Rerun 目标的 JSON payload 约定(节选):
**边界条件**:当 JSON 映射配置与本插件同时存在时优先使用插件;can_convert 返回 false 时回退至 JSON 映射管道,因此插件只需覆盖需自定义逻辑的类型。convert() 可能被多个回调线程并发调用,实现须自行保证线程安全。该插件可经环境变量 VLINK_CONVERT_PLUGIN 注入(见 13.20),可视化对接整体见 数据可视化。
SchemaPluginInterface 为 bag、MCAP、WebViz 与命令行的动态解析流水线提供统一的 schema 注册能力,覆盖 Protobuf(FileDescriptorSet 与动态消息原型)与 FlatBuffers(BFBS 与运行时 Parser)。多数情况下继承现成的 SchemaPluginBase,仅需重写 get_version_info():
Protobuf 的 generated descriptors 已随库链接,框架按类型名直接查找,无需手动注册。FlatBuffers 无全局描述符池,需将已编译进库的 BFBS 在类外静态注册一次:
进程内通过 SchemaPluginManager 单例取用,路径来自 get() 参数或环境变量 VLINK_SCHEMA_PLUGIN(见 13.20):
框架内扩展接口主要由 VLink 运行时或特定工具链在内部加载,应用代码一般不直接构造:BagPluginInterface(录制 / 回放时改写 URL 与帧,详见 录制与回放)、DiscoveryReporter(节点上线 / 下线上报,可经 VLINK_DISCOVER_DISABLE、VLINK_DISCOVER_NATIVE 控制,详见 可观测性)、ConfPluginInterface(为已识别的传输后端提供外部 Conf 工厂,不能注册新的 URL scheme,详见 传输后端与 URL)、TerminalStream(CLI 工具专用的带缓冲 stdout 单例,详见 CLI 工具)。
VLink 专有环境变量统一以 VLINK_ 前缀命名,作为运行时配置的最低优先级来源,仅在更高优先级配置缺省时生效。本节界定其优先级模型,按职责分类列出全部变量,并给出查看当前生效值的方法——C API 创建的节点、扩展加载的插件最终均受此约束。
同一项运行时配置可由三处声明,遵循就近覆盖原则。优先级由高到低如下,高优先级来源存在时覆盖低优先级来源。
| 优先级 | 来源 | 作用域 | 示例 |
|---|---|---|---|
| 高 | URL 查询参数 | 单个节点 | dds://speed?qos=sensor |
| 中 | Conf 字段 | 单类后端 | vlink::DdsConf("speed", /*domain=*/7) |
| 低 | 环境变量 | 全局进程 | VLINK_DDS_DOMAIN=7 |
由此确立两条使用原则:
dds:// → ddsc://),其语义最显式、作用域最精确。dds:// 节点整体绑定到 CycloneDDS 实现。下列变量覆盖最常见的部署调整需求,可作为快速入口。完整定义见后续分节。
| 变量 | 作用 |
|---|---|
VLINK_URL_PLUGINS | 加载额外传输后端插件(如 zenoh,ddsc),无需改代码即可启用新后端 |
VLINK_DDS_BIND | 将所有 dds:// 整体绑定到指定 DDS 实现(ddsc/ddsr/ddst) |
VLINK_INTRA_BIND | 将所有 intra:// 重定向到其他 scheme(shm/dds 等) |
VLINK_LOG_LEVEL | 全局日志级别(0=TRACE … 6=OFF) |
VLINK_DDS_IP | 指定 DDS 单播 IP,多网卡主机通常必设 |
控制插件加载、资源路径与内存池行为,与具体传输后端无关。这些变量是扩展机制的运行期注入面:VLINK_PLUGIN_DIR 影响 13.12 的搜索路径,VLINK_CONVERT_PLUGIN 注入 13.16 的转换插件、VLINK_SCHEMA_PLUGIN 注入 13.17 的 schema 插件,VLINK_URL_REMAP 等价于 13.10 的 UrlRemap 全局形式。
| 变量 | 类型 | 说明 |
|---|---|---|
VLINK_URL_PLUGINS | 名称列表 | 待加载的传输后端插件基础名(不含路径、lib 前缀与 .so 后缀),逗号或空格分隔;名称需对应已知后端(如 zenoh、ddsc),vlink- 前缀可省略 |
VLINK_SCHEMA_PLUGIN | 路径或插件名 | Schema 插件共享库路径或基础名 |
VLINK_CONVERT_PLUGIN | 路径或插件名 | 转换插件路径或基础名;WebViz 桥接及 vlink-bag2mcap/vlink-bag2rrd 在未传 --convert_plugin 时读取 |
VLINK_PROTO_DIR | 目录路径 | .proto 搜索目录,亦可经 vlink-eproto import <dir> 持久化 |
VLINK_FBS_DIR | 目录路径 | .fbs 搜索目录,亦可经 vlink-efbs import <dir> 持久化 |
VLINK_PLUGIN_DIR | 目录列表 | 插件共享库搜索目录,逗号或空格分隔,插入默认路径之前 |
VLINK_TMP_DIR | 目录路径 | 临时文件目录 |
VLINK_LOCK_DIR | 目录路径 | 锁文件目录 |
VLINK_URL_REMAP | 文件路径 | URL 重映射 JSON 文件,按子串匹配,对应 13.10 的 UrlRemap |
VLINK_INTRA_BIND | 字符串 | 将所有 intra:// 重定向到其他 scheme(shm、dds 等) |
VLINK_QOS_CONFIG | 文件路径 | 全局 QoS 配置文件路径,URL ?qos=profile 优先级更高,见 QoS 配置 |
VLINK_MEMORY_LEVEL | 数字 | 内存池档位(0..9,默认 3):0 为直通(每次直接向系统申请释放),1..9 选择内置金字塔,数值越大预留越多、常驻内存越多。仅在调用 Bytes::init_memory_pool() 构建全局内存池后生效 |
VLINK_MEMORY_PREALLOC | 1/0 | 1 时构建全局内存池时按各档 blocks_per_chunk 配额预分配满(尽力而为),消除热路径首次分配延迟;否则按需懒加载 |
内置日志系统 vlink::Logger 的级别、目录与轮转策略均可经环境变量调整。日志级别取值:0=TRACE、1=DEBUG、2=INFO、3=WARN、4=ERROR、5=FATAL、6=OFF。控制台与文件级别可分别覆盖全局级别。
| 变量 | 类型 | 说明 |
|---|---|---|
VLINK_LOG_LEVEL | 数字 | 全局日志级别(0..6) |
VLINK_LOG_CONSOLE_LEVEL | 数字 | 控制台级别,覆盖全局 |
VLINK_LOG_FILE_LEVEL | 数字 | 文件级别,覆盖全局 |
VLINK_LOG_DIR | 目录路径 | 日志文件目录 |
VLINK_LOG_CONSOLE_UNORDER | 1/0 | 非同步控制台输出,吞吐更高 |
VLINK_LOG_CONSOLE_FMT | 1/0 | 启用扩展控制台格式 |
VLINK_LOG_ENABLE_UTC | 1/0 | 使用 UTC 时间戳 |
VLINK_LOG_MAX_SIZE | 数字 | 单文件最大字节数,超过后轮转(默认 10 MiB) |
VLINK_LOG_MAX_COUNT | 数字 | 日志文件最大保留数量 |
VLINK_LOG_FLUSH_DELAY | 数字 | 刷新延迟,毫秒(默认 500) |
VLINK_LOG_PLUGIN | 插件名 | 自定义日志插件基础名,对应 13.14 的 LoggerPluginInterface |
VLINK_LOG_STORE_STRATEGY | 1/0 | 启用备用文件存储策略 |
VLINK_LOG_OPEN_APPEND | 1/0 | 启动时追加既有日志 |
VLINK_LOG_BLOCK_SYNC | 1/0 | 写入繁忙时阻塞调用线程,保证不丢日志,牺牲实时性 |
VLINK_LOG_WRITE_DEPTH | 数字 | 日志写入队列深度 |
| 变量 | 类型 | 默认 | 说明 |
|---|---|---|---|
VLINK_DISCOVER_DISABLE | 1/0 | 0 | =1 关闭节点发现,减少 UDP 广播开销 |
VLINK_DISCOVER_NATIVE | 1/0 | 0 | =1 仅发现本机节点,组播绑定到 127.0.0.1 |
VLINK_PROFILER_ENABLE | 1/0 | 0 | =1 启用内置 CPU 性能分析 |
影响 dds://、ddsc://、ddsr://、ddst:// 后端,详见 传输后端与 URL。各变量是否生效取决于当前实际启用的 DDS 实现。IP 与 peer 列表以逗号或空格分隔。
| 变量 | 类型 | 说明 |
|---|---|---|
VLINK_DDS_DOMAIN | 数字 | DDS Domain ID |
VLINK_DDS_IP | IP 列表 | DDS 单播 IP,多网卡时通常必设 |
VLINK_DDS_IP_FILTER | 1/0 | 仅使用当前可用地址 |
VLINK_DDS_MULTICAST_IP | IP 列表 | DDS 组播 IP |
VLINK_DDS_PEER | 字符串 | DDS 对等端配置 |
VLINK_DDS_BUF | 数字 | DDS 缓冲区大小 |
VLINK_DDS_MTU | 数字 | 传输层最大消息大小(MTU) |
VLINK_DDS_UDP / _TCP / _SHM | 字符串 | 对应传输层配置 |
VLINK_DDS_LESS_MEMORY | 1/0 | 低内存使用模式 |
VLINK_DDS_DEBUG | 1/0 | 启用 DDS 调试日志 |
VLINK_DDS_BIND | 字符串 | 将所有 dds:// 整体重定向到某实现:dds(Fast-DDS)、ddsf(dds 的别名)、ddsc(CycloneDDS)、ddsr(RTI Connext)、ddst(TravoDDS) |
VLINK_DDS_EVENT_QOS / _METHOD_QOS / _FIELD_QOS | 字符串 | 三种模型的默认 QoS 配置,URL ?qos=profile 优先级更高,见 QoS 配置 |
VLINK_FASTDDS_QOS_FILE | 文件路径 | Fast-DDS QoS XML 路径 |
VLINK_CYCLONEDDS_URI | URI | CycloneDDS 配置 URI |
VLINK_TRAVODDS_QOS_FILE | 文件路径 | TravoDDS(ddst://)QoS XML 路径 |
| 变量 | 类型 | 说明 |
|---|---|---|
VLINK_SHM_DEBUG | 1/0 | 启用 shm://(Iceoryx)调试日志 |
VLINK_SHM_DEPTH | 数字 | shm:// 缓冲深度 |
VLINK_SHM2_DEBUG | 1/0 | 启用 shm2://(Iceoryx2)调试日志 |
VLINK_SHM2_DEPTH | 数字 | shm2:// 缓冲深度 |
VLINK_SHM2_CONFIG | 文件路径 | Iceoryx2 配置文件路径 |
VLINK_SHM2_NOTIFY_EVERY | 数字 | 每 N 条消息通知一次消费者(默认 1);调大可批量唤醒、降低系统调用次数 |
共享内存后端依赖共享内存守护进程,推荐经 vlink-proxy -c 内嵌启动,详见 可观测性。
多值列表以逗号或空格分隔;zenoh-pico 下 VLINK_ZENOH_LISTEN 仅取首个端点。
| 变量 | 类型 | 说明 |
|---|---|---|
VLINK_ZENOH_CONFIG | 文件路径 | Zenoh JSON5 配置文件 |
VLINK_ZENOH_DOMAIN | 数字 | Zenoh Domain ID |
VLINK_ZENOH_MODE | 字符串 | 运行模式(默认 peer) |
VLINK_ZENOH_IP / _PEER / _LISTEN | 列表或字符串 | 连接 / 对等 / 监听端点 |
VLINK_ZENOH_MULTICAST / _MULTICAST_IF / _MULTICAST_TTL | 地址 / 字符串 / 数字 | 组播地址 / 网卡 / TTL |
VLINK_ZENOH_GOSSIP | 1/0 | Gossip 发现(默认 1) |
VLINK_ZENOH_ALLOWED_LOCALITY | 字符串 | 允许通信来源:local(仅会话内)/ remote(仅远端)/ 其它视作 any(默认 any),需 Z_FEATURE_UNSTABLE_API |
VLINK_ZENOH_RX_BUF / _MAX_MSG | 数字 | 接收缓冲 / 最大消息大小 |
VLINK_ZENOH_TX_QUEUE_DATA / _TX_QUEUE_RT | 数字 | 数据 / 实时发送队列深度 |
VLINK_ZENOH_LOWLATENCY / _QOS / _COMPRESSION / _TIMESTAMPS | 1/0 | 低延迟 / QoS / 压缩 / 时间戳开关 |
VLINK_ZENOH_EVENT_QOS / _METHOD_QOS / _FIELD_QOS | 字符串 | 三种模型默认 QoS 配置 |
VLINK_ZENOH_BATCH_ENABLED / _BATCH_TIME_LIMIT_MS | 布尔 / 数字 | 批量发送开关与聚合时窗 |
VLINK_ZENOH_SHM / _SHM_MODE / _SHM_SIZE / _SHM_THRESHOLD / _SHM_LOAN_THRESHOLD / _SHM_BLOCKING | 见说明 | Zenoh 共享内存:开关、初始化模式、池大小、自动提升阈值、loan 阈值、满池是否阻塞 |
| 变量 | 默认值 | 说明 |
|---|---|---|
VLINK_MQTT_BROKER | tcp://localhost:1883 | Broker 连接 URI |
VLINK_MQTT_CLIENT_ID | vlink_mqtt | 客户端 ID 前缀 |
VLINK_MQTT_DOMAIN | 0 | Domain ID |
VLINK_MQTT_QOS | 1 | MQTT QoS 级别 |
VLINK_MQTT_KEEPALIVE | 60 | 心跳保活间隔,秒 |
| 变量 | 类型 | 说明 |
|---|---|---|
VLINK_SOMEIP_CFG | 文件路径 | SOME/IP(vsomeip)配置文件路径 |
适用于启用 TLS 的连接,包括 mqtt://、dds://、ddsc://、ddsr://、zenoh://;与 13.6.3 的 vlink_ssl_options_t 一一对应,作为其全局兜底。
| 变量 | 类型 | 说明 |
|---|---|---|
VLINK_SSL_VERIFY | 1/0 | 是否验证服务器证书 |
VLINK_SSL_CA | 文件路径 | CA 证书路径 |
VLINK_SSL_CERT | 文件路径 | 客户端证书路径 |
VLINK_SSL_KEY | 文件路径 | 客户端私钥路径 |
VLINK_SSL_KEY_PASS | 字符串 | 私钥密码 |
VLINK_SSL_SNI | 字符串 | TLS SNI 主机名 |
VLINK_SSL_CIPHERS | 字符串 | 允许的密码套件列表 |
底层 DDS、SOME/IP 等中间件仍尊重各自原生环境变量,VLink 不予拦截。常见者包括 FASTDDS_DEFAULT_PROFILES_FILE、FASTDDS_BUILTIN_TRANSPORTS、FASTDDS_STATISTICS、CYCLONEDDS_URI、VSOMEIP_CONFIGURATION、VSOMEIP_APPLICATION_NAME,以及 Iceoryx 的 IOX_ROUDI_CONFIG、IOX_RUNTIME_PATH、IOX_LOG_LEVEL。其语义与默认值以各上游中间件文档为准。
**Bag 录制**(API 见 录制与回放):VLINK_BAG_PATH(文件路径,设置后启用全局录制,按后缀选择写入器——<tt>.vdb/.vdbx 数据库或 .vcap/.vcapx MCAP,后缀不支持则不启用)、VLINK_BAG_TAG(录制会话标签名)。
**基准** 仅 vlink-bench 的 process 模式生效,用于覆盖子进程协调超时,单位毫秒:VLINK_BENCH_READY_TIMEOUT_MS(默认 30000)、VLINK_BENCH_START_TIMEOUT_MS(15000)、VLINK_BENCH_MEASURE_BUFFER_MS(10000)、VLINK_BENCH_CLEANUP_TIMEOUT_MS(3000)。
**交叉编译** 仅 CMake 配置阶段读取,对运行时无影响:CROSS_COMPILE_PREFIX、CC/CXX、LINUX_INSTALL_PREFIX、SYSROOT、ANDROID_NDK/ANDROID_INSTALL_PREFIX、QNX_HOST/QNX_TARGET/QNX_INSTALL_PREFIX、OE_CMAKE_TOOLCHAIN_FILE,以及代码生成器路径 VLINK_DDSGEN_PROGRAM/VLINK_PROTOC_PROGRAM/VLINK_FLATC_PROGRAM。
**示例自定义变量** 官方示例(helloworld、ping_pong 等)读取各自的 METHOD_TRANSPORT/EVENT_TRANSPORT/METHOD_URL 等变量选择后端。下图描述示例读取环境变量并在缺省时回退默认值的流程。完整清单与运行命令见 快速开始。

环境变量可按部署形态在不同层级注入:
systemd Service 在 [Service] 段以 Environment="VLINK_LOG_LEVEL=3" 注入。
查看当前生效值使用 vlink-check env:
vlink-check env 的清单按编译时启用的模块裁剪显示,例如未启用 Zenoh 时不列 VLINK_ZENOH_*;未列出并不代表运行时不读取该变量。
examples/ 可运行示例与自定义变量