从LCM到SomeIP,再到DDS:技术演进与工作原理剖析

文章目录

    • 一、LCM:轻量级通信与编组库
      • 工作原理
      • C++ 代码示例
      • 局限性
    • 二、SomeIP:面向服务的可扩展中间件
      • 工作原理
      • C++ 代码示例
      • 优势与特点
    • 三、DDS:数据分发服务
      • 工作原理
      • C++ 代码示例
      • 优势与应用场景
    • 四、技术演进总结

在分布式系统通信领域,技术的革新日新月异,从早期的轻量级通信与编组库(LCM),到面向服务的可扩展中间件(SomeIP),再到数据分发服务(DDS),每一次的演进都带来了新的特性与能力提升。接下来,我们将深入探讨这三种技术的工作原理,并结合C++ 代码示例进行说明。

一、LCM:轻量级通信与编组库

LCM(Lightweight Communications and Marshalling)专为实时系统在高带宽和低延迟场景下的消息发送与数据封送而设计。它采用发布/订阅消息模型,特别适用于通过局域网连接的紧密耦合型系统。

工作原理

  1. 发布/订阅模型:在LCM系统中,数据发布者将特定类型的消息广播到预配置的多播组。而订阅者预先声明对某些类型消息的兴趣,当发布者发送消息时,只有订阅了相应消息类型的订阅者会接收到该消息。例如,在一个自动驾驶车辆的传感器数据采集系统中,摄像头传感器可以作为发布者,将采集到的图像数据消息发布到特定的多播组,而负责图像处理和决策的模块则作为订阅者,从该多播组接收图像数据消息。
  2. 多播机制:LCM复用UDP多播来实现高效的广播机制。多播允许数据在局域网内一次发送,多个接收者可以同时接收,大大提高了数据传输的效率,减少了网络带宽的浪费。
  3. 自动封包与解封:LCM提供自动封装/解封代码生成工具。开发者只需定义消息的数据结构,LCM就能生成相应语言(如C++ )的代码,用于将数据结构打包成网络传输的消息以及从接收到的消息中解析出数据结构。

C++ 代码示例

下面是一个简单的C++ 示例,展示如何使用LCM发送和接收消息。
首先,定义消息的数据结构:

#include "lcm/lcm-cpp.hpp"
#include <iostream>// 定义一个简单的消息结构体
struct ExampleMessage {int32_t number;double value;
};
// 为ExampleMessage注册LCM编码和解码函数
LCM_REGISTER_MESSAGE_TYPE(ExampleMessage)

然后是发布者代码:

int main() {lcm::LCM lcmInstance;if (!lcmInstance.good()) {std::cerr << "LCM initialization error" << std::endl;return 1;}ExampleMessage msg;msg.number = 42;msg.value = 3.14;// 发布消息lcmInstance.publish("EXAMPLE_CHANNEL", &msg);return 0;
}

最后是订阅者代码:

class ExampleSubscriber {
public:void handleMessage(const lcm::ReceiveBuffer* rbuf, const std::string& channel,const ExampleMessage* msg) {std::cout << "Received on channel " << channel << ": "<< "number = " << msg->number<< ", value = " << msg->value << std::endl;}
};int main() {lcm::LCM lcmInstance;if (!lcmInstance.good()) {std::cerr << "LCM initialization error" << std::endl;return 1;}ExampleSubscriber subscriber;// 订阅消息lcmInstance.subscribe("EXAMPLE_CHANNEL", &ExampleSubscriber::handleMessage, &subscriber);while (0 == lcmInstance.handle());return 0;
}

在上述代码中,发布者创建了一个ExampleMessage消息,并通过lcmInstance.publish将其发布到名为EXAMPLE_CHANNEL的通道上。订阅者则注册了对EXAMPLE_CHANNEL通道的订阅,当有消息到达时,会调用handleMessage函数处理消息。

局限性

LCM虽然在实时性和简单性方面表现出色,但它也存在一些局限性。例如,它主要适用于局域网内的通信,对于广域网场景支持不足;并且在大规模系统中,多播组的管理和消息的可靠性保障方面存在一定挑战。

二、SomeIP:面向服务的可扩展中间件

随着汽车电子等领域的发展,车辆内部网络变得越来越复杂,需要一种更高效、可扩展且基于服务导向的通信协议,SomeIP应运而生。SomeIP(Scalable service - Oriented MiddlewarE over IP)由AUTOSAR组织定义,旨在通过IP网络实现车载电子控制单元(ECU)之间的服务化通信。

工作原理

  1. 服务导向模型:SomeIP将车载功能抽象为“服务”。一个服务由服务接口定义,包含方法(客户端主动调用的功能,如获取车速)、事件(服务端主动推送的通知,如车速超过阈值)和字段(可读写的状态变量,如当前温度)。服务通过服务ID唯一标识,其内部元素也有各自的ID进行区分。例如,在汽车的智能驾驶系统中,自动泊车功能可以作为一个服务,其中启动自动泊车操作可以是一个方法,泊车过程中的状态变化(如接近障碍物)可以通过事件通知相关模块。
  2. 服务发现机制:SomeIP - SD(Service Discovery)负责服务的动态发现与管理。服务提供方(Server)通过广播“Offer Service”消息来广告自己提供的服务;服务消费方(Client)则通过广播“Find Service”消息来查询所需服务。并且采用定时刷新机制来确保服务状态的时效性,例如Server每T秒(T通常为1 - 10秒,可配置)重发一次“Offer Service”消息,Client在超过一定时间(通常为3 * T)未收到新广告时,标记服务为“不可用”。
  3. 消息交互:SomeIP定义了多种消息类型,包括请求(Request)、响应(Response)、通知(Notification)等。消息帧由头部和载荷(payload)组成,头部包含消息ID(高16位为服务ID,低16位为方法/事件/字段ID + 类型标识)、会话ID(用于关联请求与响应)等关键控制信息;载荷则为业务数据,其格式由应用定义并需遵循序列化规则,例如字节序采用大端(Big - Endian,网络字节序),对齐方式采用自然对齐以确保不同ECU能正确解析。传输层可选择UDP(低延迟,适合实时数据)或TCP(可靠传输,适合关键指令)。

C++ 代码示例

下面是一个简化的C++ 示例,展示SomeIP服务端和客户端的基本操作。
首先是服务端代码,假设定义一个提供获取车速服务的服务端:

#include <iostream>
// 引入SomeIP相关库,这里假设库名为someip_library
#include "someip_library/someip_server.hpp"// 定义获取车速的方法处理函数
int32_t getSpeedHandler() {// 模拟获取车速,这里返回一个固定值return 60;
}int main() {someip::Server server;// 注册服务和方法server.registerService(1234, "SpeedService");server.registerMethod(1234, 5678, "getSpeed", getSpeedHandler);// 启动服务server.start();while (true);return 0;
}

然后是客户端代码,用于调用获取车速的服务:

#include <iostream>
#include "someip_library/someip_client.hpp"int main() {someip::Client client;// 查找服务client.findService(1234, "SpeedService");// 调用方法获取车速int32_t speed = client.callMethod<int32_t>(1234, 5678, "getSpeed");std::cout << "Current speed: " << speed << " km/h" << std::endl;return 0;
}

在上述代码中,服务端通过registerServiceregisterMethod注册了一个名为“SpeedService”的服务及其“getSpeed”方法,并在启动后等待客户端调用。客户端则通过findService查找服务,然后使用callMethod调用服务的方法获取车速。

优势与特点

SomeIP的优势在于其可扩展性,能够适应不同规模的车载网络。它以服务为导向的设计使得车载系统的功能划分更加清晰,易于维护和升级。同时,服务发现机制解决了车载网络中ECU启动顺序不确定和服务动态上下线的问题。然而,SomeIP本身未定义安全机制,在安全性要求较高的场景下,需要额外的安全措施,如后续提出的SomeIP - Sec(Secure SOME/IP)来保障通信安全。

三、DDS:数据分发服务

DDS(Data Distribution Service)是对象管理组织(OMG)定义的标准,旨在为分布式实时系统提供高性能、可扩展的数据分发服务。它在工业自动化、航空航天、智能交通等领域得到广泛应用。

工作原理

  1. 数据中心发布/订阅模型:DDS采用数据中心发布/订阅模型,发布者和订阅者通过“主题(Topic)”进行数据交互。主题定义了数据的类型和语义,发布者将数据发布到特定主题,订阅者则订阅感兴趣的主题。与LCM不同的是,DDS具有更强大的发现协议,发布者可以自动发现合适的订阅者,并且消息只会路由到这些订阅者,而不是像LCM那样广播到预配置的多播组。例如,在一个智能工厂的生产线上,不同的传感器可以将各自采集的数据(如温度、压力等)发布到对应的主题,而负责数据分析和控制的系统则订阅相关主题获取数据。
  2. 服务质量(QoS)策略:DDS提供丰富的QoS策略,允许用户根据应用需求定制数据传输的特性。例如,可靠性策略可以选择可靠传输(确保数据不丢失)或尽力而为传输(适合对实时性要求极高但能容忍少量数据丢失的场景);持久性策略可以决定当订阅者离线时,发布者的数据是否保存并在订阅者重新上线时补发;截止期限策略可以规定数据必须在多长时间内送达订阅者等。
  3. 数据表示与传输:DDS支持多种数据表示格式,并且对数据进行高效的序列化和反序列化,以减少网络传输的开销。同时,它能够在不同的网络协议(如UDP、TCP等)上运行,适应不同的网络环境。

C++ 代码示例

下面是一个简单的C++ 示例,展示DDS的发布者和订阅者操作。假设使用的是一个开源的DDS库(这里假设库名为open_dds)。
发布者代码:

#include <iostream>
#include "open_dds/dds/pub/ddspub.hpp"
#include "open_dds/dds/core/ddscore.hpp"// 定义数据结构
struct SensorData {double temperature;double pressure;
};// 注册数据类型
DDS_REGISTER_TYPE(SensorData)int main() {dds::domain::DomainParticipant participant(0);dds::topic::Topic<SensorData> topic(participant, "SensorDataTopic");dds::pub::Publisher publisher(participant);dds::pub::DataWriter<SensorData> writer(publisher, topic);SensorData data;data.temperature = 25.5;data.pressure = 1013.25;// 发布数据writer.write(data);return 0;
}

订阅者代码:

#include <iostream>
#include "open_dds/dds/sub/ddssub.hpp"
#include "open_dds/dds/core/ddscore.hpp"struct SensorData {double temperature;double pressure;
};DDS_REGISTER_TYPE(SensorData)int main() {dds::domain::DomainParticipant participant(0);dds::topic::Topic<SensorData> topic(participant, "SensorDataTopic");dds::sub::Subscriber subscriber(participant);dds::sub::DataReader<SensorData> reader(subscriber, topic);SensorData data;// 接收数据dds::sub::LoanedSamples<SensorData> samples = reader.take();for (const auto& sample : samples) {if (sample.info().valid()) {data = sample.data();std::cout << "Received: Temperature = " << data.temperature<< ", Pressure = " << data.pressure << std::endl;}}return 0;
}

在上述代码中,发布者创建了一个SensorData类型的数据,并通过writer.write将其发布到名为“SensorDataTopic”的主题上。订阅者则从该主题接收数据,通过reader.take获取数据样本并进行处理。

优势与应用场景

DDS的优势在于其高度的灵活性和可定制性,通过丰富的QoS策略能够满足各种复杂实时应用的需求。在航空航天领域,飞机的飞行控制系统需要实时、可靠地获取各种传感器数据,DDS的可靠传输和低延迟特性能够保障飞行安全;在智能交通系统中,车辆之间以及车辆与基础设施之间的通信对实时性和数据准确性要求极高,DDS的高效数据分发和QoS策略可以确保交通信息的及时传递和处理。

四、技术演进总结

从LCM到SomeIP,再到DDS,我们可以看到分布式系统通信技术在不断演进。LCM作为轻量级的通信库,为实时系统提供了基本的发布/订阅通信能力,但其应用场景相对局限于局域网内的紧密耦合系统。SomeIP则是为了解决车载网络等特定领域的通信需求而诞生,以服务导向的设计和服务发现机制适应了复杂车载网络中功能的抽象与管理,但在安全机制方面存在不足。DDS则更加通用和强大,通过数据中心发布/订阅模型和丰富的QoS策略,能够满足各种复杂实时应用在不同网络环境下的通信需求,在工业、交通、航空航天等多个领域展现出巨大的优势。随着技术的不断发展,未来分布式系统通信技术有望在性能、安全性、可扩展性等方面取得更大的突破,为更多创新应用提供坚实的基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/91987.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/91987.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis里面什么是sdshdr,可以详细介绍一下吗?

文章目录为什么 Redis 不直接使用 C 语言的字符串&#xff1f;sdshdr 的结构sdshdr 的不同类型sdshdr 带来的优势总结我们来详细解析一下 Redis 的核心数据结构之一&#xff1a; sdshdr。sdshdr 是 “Simple Dynamic String header” 的缩写&#xff0c;意为“简单动态字符串头…

RocketMq如何保证消息的顺序性

文章目录1.顺序消息的全流程1.1 发送阶段&#xff1a;消息分区1.2.存储阶段&#xff1a;顺序写入1.3.消费阶段&#xff1a;串行消费2.第三把锁有什么用?3.顺序消费存在的问题和Kafka只支持同一个Partition内消息的顺序性一样&#xff0c;RocketMQ中也提供了基于队列(分区)的顺…

zabbix平台无法删除已停用主机的处理案例

在zabbix平台上删除已停用的主机&#xff0c;提示“SQL描述式执行已失败: "DELETE FROM items WHERE (itemid IN &#xff08;.....)”&#xff0c;无法删除&#xff0c;本文为处理情况。一、问题现象在zabbix平台上删除已停用的主机&#xff0c;提示“SQL描述式执行已失败…

【计算机网络】6应用层

1.网络应用模型 特性 客户/服务器模型(Client-Server, C/S) 对等模型(Peer-to-Peer, P2P) 中心化 是(依赖服务器) 否(去中心化) 角色特点 服务器 客户机 无中心服务器 提供计算服务 请求计算服务 每个节点(Peer)既是客户机也是服务器 永久在线 间歇接入网络 节点间…

基于 Spring Boot + Vue 实现人脸采集功能全流程

一、技术栈与依赖引入 后端依赖 (pom.xml) <!-- 百度AI SDK --> <dependency><groupId>com.baidu.aip</groupId><artifactId>java-sdk</artifactId><version>4.16.19</version><exclusions><exclusion><grou…

《Python基础》第3期:使用PyCharm编写Hello World

我们写文档大多用 Word、写表格大多用 Excel、写幻灯片大多用 PPT。 写代码也需要一个软件作为编辑器&#xff08;传说的大神用记事本写代码纯属玩笑了&#xff0c;越是大神越追求效率&#xff0c;用的软件功能越强&#xff09;。 Python 现在已经有了非常多的代码编辑器&#…

我的第一个开源项目:排序算法的多种实现方式

以 排序算法 为例&#xff0c;展示如何在 Python 中进行不同实现方式的对比项目概述本项目旨在通过 Python 实现几种经典的排序算法&#xff0c;并通过性能对比、代码注释和优化手段&#xff0c;为开源社区提供参考。选择排序、冒泡排序、快速排序和归并排序作为主要算法&#…

5G-LEO - 用于 5g satellite 链接的 OpenAirInterface™ 扩展

目标&#xff1a;5G-LEO 旨在加速 OAI 作为开源工具的发展&#xff0c;允许卫星通信社区交流和比较 5G NTN 结果&#xff0c;并促进研发活动的合作。扩展的OAI软件库被视为开发早期原型的重要工具&#xff0c;用于验证关键的5G NTN设计方面&#xff0c;并为3GPP标准化过程提供及…

基于 Mybatis 框架*的完整开发流程与顺序

基于 MyBatis 框架 的完整开发流程与顺序一、环境准备阶段1. 新建 Maven 项目&#xff08;或普通 Java 项目&#xff09;作用&#xff1a;用 Maven 统一管理依赖&#xff0c;自动下载 MyBatis、MySQL 驱动等 Jar 包操作&#xff1a;IDE&#xff08;如 IDEA&#xff09;选 Maven…

机械学习--决策树(实战案例)

决策树分两种分类和回归&#xff0c;这篇博客我将对两种方法进行实战讲解一、分类决策树代码的核心任务是预测 “电信客户流失状态”&#xff0c;这是一个典型的分类任务数据集附在该博客上&#xff0c;可以直接下载代码整体结构整理代码主要分为以下几个部分&#xff1a;导入必…

SQL154 插入记录(一)

描述牛客后台会记录每个用户的试卷作答记录到exam_record表&#xff0c;现在有两个用户的作答记录详情如下&#xff1a;用户1001在2021年9月1日晚上10点11分12秒开始作答试卷9001&#xff0c;并在50分钟后提交&#xff0c;得了90分&#xff1b;用户1002在2021年9月4日上午7点1分…

BeanFactory 和 ApplicationContext 的区别?

口语化答案好的&#xff0c;面试官。BeanFactory和ApplicationContext都是用于管理Bean的容器接口。BeanFactory功能相对简单。提供了Bean的创建、获取和管理功能。默认采用延迟初始化&#xff0c;只有在第一次访问Bean时才会创建该Bean。因为功能较为基础&#xff0c;BeanFact…

VNC连接VirtualBox中的Ubuntu24.04 desktop图形化(GUI)界面

测试环境&#xff1a;VirtualBox 7,Ubuntu24.04 desktop,Ubuntu24.04 server(no desktop) 一、下载和安装dRealVNC viewer。 二、配置 VirtualBox 网络&#xff1a;NAT 模式 端口转发 1、打开 VirtualBox&#xff0c;选择您的 Ubuntu 虚拟机&#xff0c;点击 设置。 选择 网…

浮动路由和BFD配置

拓扑图 前期的拓扑图没有交换机配置步骤 1、配置IP地址 终端IP地址的配置 路由器IP地址的配置 配置router的对应接口的IP地址 <Huawei>sys [Huawei]sysname router [router]interface Ethernet 0/0/0 [router-Ethernet0/0/0]ip address 192.168.10.254 24 [router-Ethern…

Docker 实战 -- Nextcloud

文章目录前言1. 创建 docker-compose.yml2. 启动 Nextcloud3. 访问 Nextcloud4. 配置优化&#xff08;可选&#xff09;使用 PostgreSQL使用 redis添加 Cron 后台任务5. 常用命令6. 反向代理&#xff08;Nginx/Apache&#xff09;前言 当你迷茫的时候&#xff0c;请点击 Docke…

【计算机网络 | 第2篇】计算机网络概述(下)

文章目录七.因特网服务提供商&#x1f95d;八.接入网&#x1f95d;主流的家庭宽带接入方式介入网工作原理&#x1f9d0;DSL技术&#xff1a;铜线上的“三通道”通信DSL的速率标准呈现出显著的"不对称"特征&#x1f914;电缆互联网接入技术&#x1f34b;‍&#x1f7e…

SpringMVC 6+源码分析(四)DispatcherServlet实例化流程 3--(HandlerAdapter初始化)

一、概述 HandlerAdapter 是 Spring MVC 框架中的一个核心组件&#xff0c;它在 DispatcherServlet 和处理程序&#xff08;handler&#xff09;之间扮演适配器的角色。DispatcherServlet 接收到 HTTP 请求后&#xff0c;需要调用对应的 handler 来处理请求&#xff08;如控制器…

【lucene】FastVectorHighlighter案例

下面给出一套可直接拷贝运行的 Lucene 8.5.0 FastVectorHighlighter 完整示例&#xff08;JDK 8&#xff09;&#xff0c;演示从建索引、查询到高亮的全过程。 > 关键点&#xff1a;字段必须 1. 存储原始内容&#xff08;setStored(true)&#xff09; 2. 开启 TermVecto…

C++返回值优化(RVO):高效返回对象的艺术

在C开发中&#xff0c;按值返回对象的场景十分常见&#xff08;如运算符重载、工厂函数等&#xff09;&#xff0c;但开发者常因担忧“构造/析构的性能开销”而陷入纠结&#xff1a;该不该返回对象&#xff1f;如何避免额外成本&#xff1f;本文将剖析痛点、拆解错误思路&#…

用 PyTorch 实现一个简单的神经网络:从数据到预测

PyTorch 是目前最流行的深度学习框架之一&#xff0c;以其灵活性和易用性受到开发者的喜爱。本文将带你从零开始&#xff0c;用 PyTorch 实现一个简单的神经网络&#xff0c;用于解决经典的 MNIST 手写数字分类问题。我们将涵盖数据准备、模型构建、训练和预测的完整流程&#…