DDS通信协议与安全实践
Posted sam.li
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DDS通信协议与安全实践相关的知识,希望对你有一定的参考价值。
DDS(Data Distribution Service)是一套通信协议和 API 标准;它提供了以数据为中心的连接服务,基于发布者-订阅者模型。这是一套中间件,它提供介于操作系统和应用程序之间的功能,使得组件之间可以互相通信。并且提供了低延迟,高可靠的通信以及可扩展的架构。
DDS本身是一套标准。由Object Management Group(简称OMG)维护。OMG是一个开放性的非营利技术标准联盟,由许多大型IT公司组成:包括IBM,Apple Computer,Sun Microsystems等。但OMG仅仅负责制定标准,而标准的实现则由其他服务提供商完成。目前DDS的提供商有很多:Vortex OpenSplice,eProsima Fast RTPS,Hamersham,Company Summary Kongsberg Gallium,MilSOFT,Object Computing OpenDDS,Remedy IT,RTI,Twin Oaks Computing, Inc.。
DDS 在网络栈中的位置
这个图之所以是沙漏形状是因为:两头的技术变化都发展很快,但是中间的却鲜有变化。
DDS 如何降低系统复杂度
-
传统分布式系统采用点对点的方案,会面临通道数量爆炸式增长问题:
-
而采用 DDS,拥有统一的 DDS DataBus,随着新节点的加入,不会增加拓扑的复杂度;
-
采用基于 DDS 的上层应用,能极大简化复杂度;
FastDDS
eProsima Fast DDS 目前已经被选为 Robot Operating System 2 (ROS 2) 系统的默认中间件并且被包含在最新发布版本Foxy Fitzroy中。
特性
- 两个 API 层:包含专注可用性的上层DDS层,以及聚焦通道的底层RTPS层;
- 实时性(即插即连):提供实时特性,无论是发现,上线,下线,发送消息都能实时响应,并支持随时入网/出网;
- 同步/异步的数据发送模式;
- 可靠通信:即使在UDP通道上,也可支持可靠的通信范式;此外,也可以采用 TCP 通道;
- 传输层:UDPv4, UDPv6, TCPv4, TCPv6, SHM;
- 安全:可配置的安全通信,实现3个方面的安全配置:远程校验,访问控制,数据加密;
- 灵活性&拓展性:DDS 建立在全局数据空间的概率上,有良好的灵活性以及拓展性;
- 可移植性:通用的 RTPC 协议支持各 DDS 实现的互通,同时也支持写一遍代码运行于多个平台;
- 可配置:可以通过代码或者 XML 文件进行配置;
- 高性能:采用 FastCDR 作为序列化库;
- 统计模块
- 流量控制
- 免费开源
架构
如下图所示,FastDDS 大致可分为4层:
-
应用层:提供用户友好的 API
-
FastDDS 层
-
以数据为中心的模型,虚拟出全局数据空间的概念,各节点向该空间声明发布者或者订阅者的意图;
-
抽象出 Domain 以及 Topic 的概念,不同 Domain 之间数据独立不互通,在同一个 Domain 之间通过 Topic 发布/订阅数据;
-
-
-
RTPS 层(作为通道层的抽象)
-
由 OMG 联盟定义和维护,以确保不同 DDS 供应商应用程序之间可以互通;
-
基于 TCP/UDP/IP 等传输协议,提供订阅/发布通道;
-
-
通道层
DDS
Entity
-
在 DDS 中,Entity 是一个抽象基类,表示支持 Qos 策略,listener 以及 状态的实体,它有许多实现:
-
不同的 Entity 实现有不同的回调,可以从回调中看到各实体的能力:
Domain
-
一个 Domain 相当于一个独立的数据交互平台,可以看作是虚拟网络;实现多个独立的应用在同一套物理网络中共存。可以类比于 VPS(虚拟机),同一台主机上的多个 VPS 共用硬件设备,但各 VPS 之间是独立的;
-
每个 Domain 都有独立的 domainId,只有 domainId 相同的应用才能互相通信;
-
Domain 在 FastDDS 中,使用 DomainParticipant 来管理;
Partitions
- Partitions 是在 Domain 中引入的逻辑隔离,可以作用在 PublisherQos 和 SubscriberQos 上,定义了 Partitions 后,在订阅匹配上不仅要求 Topic 匹配,还要求 Partitions 匹配;
- 如果没有定义 Partitions,会自动包含在默认分区中;
- 每个 Entity(Publisher/Subscriber) 可以在多个 Partitions 中;
- Partitions 名支持通配符;看匹配示例;
Publisher
一个 Domain 可以创建多个 Publisher,每个 Publisher 可以创建多个 DataWriter,而一个 DataWriter 只能绑定一个 Topic
Topic
Topic 是作为订阅/发布模式的最基本的单位;
-
Publisher/Subscriber 于 Topic 都是一对一的关系;
-
在 Topic 中,还有更细分的 Instance 概念,查看 RTI 介绍的 什么是 DDS Samples, Instances, and Keys
-
什么是 instance:
-
什么是 key:在 IDL 文件中,可以定义当前数据的 key(和数据库有点像),比如:
struct HelloWorld // Unique ID: airline name @key string<256> airline_name; // Unique ID: flight number @key short flight_number; // Coordinates double latitude; double longitude; double altitude; ;
-
什么是sample:在 DDS 中流通的每条数据都是一个 sample;
-
instance :对定义过 key 的 sample 集合可以统一独立管理,这就是 instance;
-
-
instance 在数据流中的示例:
-
instance 的使用,查看 RTI 介绍的 Managing Data Instances;
register_instance()
:会返回InstanceHandle_t
,用来管理 instance;unregister_instance()
write()
dispose()
-
instance 生命周期:
-
为什么要用 instance:在往某个 topic 发送数据的时候,DDS 会检查该数据属于哪个 instance;指定 instance 可以提高性能,节约内存;
-
Qos
Qos 基本上负责了 DDS 的所有配置,无论是心跳,消息可靠性,流量控制,还是安全配置,甚至包括通道配置,全是通过 Qos 来实现的。
配置新加入节点对已发送数据的接受规则;
- VOLATILE_DURABILITY_QOS:不保留已发送数据;
- TRANSIENT_LOCAL_DURABILITY_QOS:保留已发送数据,当有新 DataReader 加入,会把内存中的历史数据全部发给它;
- TRANSIENT_DURABILITY_QOS:在上述基础上,持久化到本地,这样就不会丢数据了;
ReliabilityQosPolicy
配置通道的可靠性;
-
BEST_EFFORT_RELIABILITY_QOS:尽力而为,不保证数据可靠性;适合视频流等数据;
-
RELIABLE_RELIABILITY_QOS:保证可靠性;会等待 remote 的到达确认,如果数据丢失会重传;
-
max_block_time:当发送队列由于“未确认消息”而满的时候,DataWriter 的
write()
操作可能会阻塞,这里设置最长阻塞时长,超时会报写入错误; -
DataWriter 和 DataReader 的 QOS 需要配对使用,如下:
-
DataWriter kind | DataReader kind | Compatibility |
---|---|---|
BEST_EFFORT_RELIABILITY_QOS | BEST_EFFORT_RELIABILITY_QOS | Yes |
BEST_EFFORT_RELIABILITY_QOS | RELIABLE_RELIABILITY_QOS | No |
RELIABLE_RELIABILITY_QOS | BEST_EFFORT_RELIABILITY_QOS | Yes |
RELIABLE_RELIABILITY_QOS | RELIABLE_RELIABILITY_QOS | Yes |
HistoryQosPolicy
配置已发送数据的缓存规则;
该策略行为会受到 ResourceLimitsQosPolicy 配置的影响;
-
KEEP_LAST_HISTORY_QOS:保留最新depth条数据; depth 需满足:
depth < ResourceLimitsQosPolicy.max_samples_per_instance
-
KEEP_ALL_HISTORY_QOS:保留所有历史数据;如果资源受限,后续行为会受 ReliabilityQosPolicy 的影响;
ResourceLimitsQosPolicy
配置终端对某个 Topic 的资源限制;
参数 | 说明 |
---|---|
max_samples | 最大 sample 数 |
max_instances | 最大 instance 数量 |
max_samples_per_instance | 每个 instance 可以管理的最大 sample 数 |
allocated_samples | 初始 sample 数 |
extra_samples | 缓存池中额外 smaple 数;因此缓存池最大数量为 max_samples + extra_sample |
LifespanQosPolicy
数据的生命周期(过期时间),默认不过期;
过期的数据 DataWriter 就不会再投递,并且从DataWriter/DataReader 的 history 中清除;
LivelinessQosPolicy
配置超时策略
- kind
- AUTOMATIC_LIVELINESS_QOS:只要连接存在,就认为存活;
- MANUAL_BY_PARTICIPANT_LIVELINESS_QOS:只要 remote DomainParticipant 响应,就认为存活;
- MANUAL_BY_TOPIC_LIVELINESS_QOS:需要 remote 对应 Topic 响应,才认为存活;
- lease_duration:超时时间,超过这个时间没有收到心跳包,则认为超时;
- announcement_period:只有 kind 为 上述 1或者2才会生效,表示发送心跳包之间的时间间隔;
DeadlineQosPolicy
指定消息的更新频率,当新消息的频率降至某个阈值以下时,会发出警报。这对于需要定期更新数据的场景很有用
DestinationOrderQosPolicy
当多个 DataWriter 对同一个 Topic 发送相同 key 消息的时候,需要定义接收端的排序方式
- BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS:按接收端接收时间排序,可能会导致不同终端数据因为接收顺序不一致而导致数据的不一致;
- BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS:按发送端的发送时间戳排序,可以保证多终端数据的一致性;
OwnershipQosPolicy
对某个 Instance 配置是否允许多端同时下发;
- SHARED_OWNERSHIP_QOS:允许多终端同时下发;
- EXCLUSIVE_OWNERSHIP_QOS:不允许多终端同时下发,在某个时间点,只允许一个终端下发数据;而允许下发的终端是可动态变化的;
PartitionQosPolicy
Partitions 是在 Domain 中引入的逻辑隔离;可以作用在 PublisherQos 和 SubscriberQos 上;
PartitionQosPolicy partitions;
//The PartitionsQosPolicy is default constructed with max_size = 0.
//Max_size is a private member so you need to use getters and setters to access
//Change the max_size to 20
partitions.set_max_size(20); //Setter function
//The PartitionsQosPolicy is default constructed with an empty list of partitions
//Partitions is a private member so you need to use getters and setters to access
//Add new partitions
std::vector<std::string> part = partitions.names();
part.push_back("part1");
part.push_back("part2");
partitions.names(part); //Setter function
FlowControllersQos
流量控制
-
scheduler:
- FIFO:先 write,先发送;
- ROUND_ROBIN:循环所有 DataWriter,每次只发一条 sample;
- HIGH_PRIORITY:根据优先级,高优先级优先发送;
- PRIORITY_WITH_RESERVATION:在上述 HIGH_PRIORITY 的基础上,预留一定的带宽资源给当前 DataWritter 使用;
-
max_bytes_per_period:单位 period_ms 时间内,最大能发送的数据量(bytes);
-
period_ms:时长,单位 milliseconds;
-
Example:
// Limit to 300kb per second. static const char* flow_controller_name = "example_flow_controller"; auto flow_control_300k_per_sec = std::make_shared<eprosima::fastdds::rtps::FlowControllerDescriptor>(); flow_control_300k_per_sec->name = flow_controller_name; flow_control_300k_per_sec->scheduler = eprosima::fastdds::rtps::FlowControllerSchedulerPolicy::FIFO; flow_control_300k_per_sec->max_bytes_per_period = 300 * 1000; flow_control_300k_per_sec->period_ms = 1000; // Register flow controller on participant DomainParticipantQos participant_qos; participant_qos.flow_controllers().push_back(flow_control_300k_per_sec); // .... create participant and publisher // Link writer to the registered flow controller. // Note that ASYNCHRONOUS_PUBLISH_MODE must be used DataWriterQos qos; qos.publish_mode().kind = ASYNCHRONOUS_PUBLISH_MODE; qos.publish_mode().flow_controller_name = flow_controller_name;
PublishModeQosPolicy
- SYNCHRONOUS_PUBLISH_MODE:同步发送数据;
- ASYNCHRONOUS_PUBLISH_MODE:异步发送数据;
发现协议
发现机制
发现机制 | 简介 |
---|---|
Simple Discovery (默认) | 分为 SPDP、SEDP 两个阶段 |
Discovery Server | 集中式发现体系结构 |
Static Discovery | 使用 SPDP,而 EDP 需要手工(XML)配置 |
Manual Discovery | 位于 RTPS 层,全手动配置 |
Discovery Server 和 Simple Discovery 的比较:
发现步骤(SIMPLE)
-
向指定的多播地址(默认 239.255.0.1)发送本机 DomainParticipants 信息,主要包含下图中的 DomainId,单播地址等;
这个信息会循环发送
- 在 DomainParticipants 创建期间,默认以 100ms 间隔持续发送,可以通过
discovery_config.initial_announcements.period
设置; - Participants 创建完毕后,默认会以 3秒 的间隔持续发送;可通过
discovery_config.leaseDuration_announcementperiod
设置;
- 在 DomainParticipants 创建期间,默认以 100ms 间隔持续发送,可以通过
-
加入多播组(239.255.0.1),以接受多播消息;
-
按照 RTPS 标准,每个 Participant 需要监听 2个端口;当然,端口号可以并存预设,以及计算规则的修改;
-
单播端口:
unicast_port = 7400 + 250 * domainID + 10 + 2 * participantID
; -
多播端口:
这里设计巧妙的一点,不同 domainID 使用的多播端口号是不同的,所以不同 domain 之间数据是隔离的(不会互相发现);而且相同 domain 不同终端之间计算出来的多播端口号是一致的,所以可以直接找到对方而不用过滤;multicast_port = 7400 + 250 * domainId + 0
-
-
总体Simple Discovery机制的发现步骤如下,其中多播并不是必要的,如果初始化的时候可以内置单播地址以及端口,就可以禁用多播通道;
超时
默认 20 秒,可以通过discovery_config.leaseDuration
配置;
通道层
默认通道
FastDDS 默认开启 UDP & SHM 通道,可以设置 use_builtin_transports = false
关闭;
UDP 通道
DomainParticipantQos qos;
// Create a descriptor for the new transport.
auto udp_transport = std::make_shared<UDPv4TransportDescriptor>();
udp_transport->sendBufferSize = 9216;
udp_transport->receiveBufferSize = 9216;
udp_transport->non_blocking_send = true;
// Link the Transport Layer to the Participant.
qos.transport().user_transports.push_back(udp_transport);
// Avoid using the default transport
qos.transport().use_builtin_transports = false;
TCP 通道
TCP 通道可以实现广域网中 DDS 的使用,区分客户端以及服务端,不同的端需要不同配置;
-
服务端配置
DomainParticipantQos qos; // Create a descriptor for the new transport. auto tcp_transport = std::make_shared<TCPv4TransportDescriptor>(); tcp_transport->sendBufferSize = 9216; tcp_transport->receiveBufferSize = 9216; tcp_transport->add_listener_port(5100); tcp_transport->set_WAN_address("80.80.99.45"); // Link the Transport Layer to the Participant. qos.transport().user_transports.push_back(tcp_transport); // Avoid using the default transport qos.transport().use_builtin_transports = false;
-
客户端配置:
DomainParticipantQos qos; // Disable the built-in Transport Layer. qos.transport().use_builtin_transports = false; // Create a descriptor for the new transport. // Do not configure any listener port auto tcp_transport = std::make_shared<TCPv4TransportDescriptor>(); qos.transport().user_transports.push_back(tcp_transport); // Set initial peers. Locator_t initial_peer_locator; initial_peer_locator.kind = LOCATOR_KIND_TCPv4; IPLocator::setIPv4(initial_peer_locator, "80.80.99.45"); initial_peer_locator.port = 5100; qos.wire_protocol().builtin.initialPeersList.push_back(initial_peer_locator); // Avoid using the default transport qos.transport().use_builtin_transports = false;
-
经过测试,在同一个 Domain 中开启 TCP 以及 UDP 通道,只会有一个通道生效(前一个),这2个并不能共存;所以如果需要通过云端将多个局域网连接在一起,需要使用独立的 TCP Domain 作为隧道打通局域网;
安全
FastDDS 提供5个安全构建时插件,分别是 身份鉴定,访问控制,数据加密,日志,数据标签;
身份鉴定
- 需要用到的几个证书
证书配置 | 说明 |
---|---|
identity_ca | DDS 使用的根证书,所有 DDS 客户端共用一份;本证书私钥需要管理员自行保存; |
identity_certificate | DomainParticipant 使用的证书,需要被 identity_ca(根证书)签名,各终端互相独立; |
identity_crl (可选) | 过期的证书列表 |
private_key | DomainParticipant 证书私钥,对应上述identity_certificate证书;需要配置到终端中; |
password (可选) | 私钥密码,可以将上述 private_key 加密,这里传入密码; |
-
初始化证书
-
根证书(identity_ca):可以内置,或者在终端首次运行时从服务端获取;用来在发现期间验证其他 DomainParticipant 证书合法性;
-
DomainParticipant 证书(identity_certificate):在终端首次运行时自动生成,本地保存好私钥;然后将生成的证书上传服务器请求签名,服务器使用根证书签名后返回;后续 DomainParticipant 就可以使用这个证书进行发现服务的身份鉴定;
sequenceDiagram participant C as Client participant S as 证书服务器 C->>C: 首次运行,生成“私钥A”及“CA证书A”(identity_certificate) Note over C: 将“私钥A”储存<br>于安全区域 C->>S: 将“CA证书A”上传至证书服务器 S->>S: 使用根证书私钥签名“CA证书A”,得到“CA证书B” S->>C: 返回“CA证书B” C->>C: 保存“CA证书B”(没有安全要求)
-
-
身份鉴定
-
DomainParticipant 初始化:
- 在调用
create_participant
方法创建 DomainParticipant 的时候,会进入自检流程,自检完成会生成IdentityToken
,PermissionsToken
等,然后交给发现服务使用; validate_local_identity()
(#70,#192)
:- 使用根证书,验证本地 DomainParticipant 的identity_certificate证书合法性;
- 该方法需要返回当前 participant 的句柄
IdentityHandle
,以及在 DDS 网络中唯一的身份标识GUID_t
;
- 在调用
-
进入握手环节:
-
validate_remote_identity()
(#193)
:-
验证
remote_identity_token
和local_identity_token
是否一致; -
比较
participant_guid
if (remote_participant_guid > local_participant_guid) return VALIDATION_PENDING_HANDSHAKE_REQUEST; // 下一步:begin_handshake_request else return VALIDATION_PENDING_HANDSHAKE_MESSAGE; // 下一步:等待
-
-
HandShakeMessageToken
有3种格式(#187)
: -
begin_handshake_reply
(#194)
:- 使用根证书验证 remote 证书
HandShakeRequestMessageToken.c.id
; - 生成 dh1 = DH publicKey,生成随机数保留本地,然后将 dh1 发给 remote;
- 使用根证书验证 remote 证书
-
begin_handshake_request.process_handshake
:- 使用根证书验证 remote 证书;
- 生成随机数保留本地,计算 dh2 发给 remote;
- 使用本地随机数,以及 dh1 生成共享对称密钥;
-
begin_handshake_replay.process_handshake
: 使用本地随机数,以及 dh2 生成共享对称密钥; -
get_shared_secret()
:获得协商后的对称加密密钥;
-
-
-
终端配置
DomainParticipantQos pqos; // 启用“身份鉴定”插件: pqos.properties().properties().emplace_back("dds.sec.auth.plugin", "builtin.PKI-DH"); // 配置根证书: pqos.properties().properties().emplace_back( "dds.sec.auth.builtin.PKI-DH.identity_ca", "file://identity_ca.pem"); // 配置终端证书: pqos.properties().properties().emplace_back( "dds.sec.auth.builtin.PKI-DH.identity_certificate", "file://identity_certificate.pem"); // 终端证书私钥: pqos.properties().properties().emplace_back( "dds.sec.auth.builtin.PKI-DH.private_key", "file://private_key.pem");
访问控制
- 需要用到的几个文件
配置 | 说明 |
---|---|
permissions_ca | 权限根证书(可以共用上面的identity_ca),下面2个文件都需要被此证书加签 |
governance | 配置数据加密方式,加密等级等 |
permissions | 访问权限配置 |
-
配置数据在 DDS 中的加密方式,加密等级,加密范围;
<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:noNamespaceSchemaLocation="omg_shared_ca_domain_governance.xsd"> 3 <domain_access_rules> 4 <domain_rule> 5 <domains> 6 <id_range> 7 <min>0</min> 8 <max>230</max> 9 </id_range> 10 </domains> 11 <allow_unauthenticated_participants>false</allow_unauthenticated_participants> 12 <enable_join_access_control>true</enable_join_access_control> 13 <discovery_protection_kind>ENCRYPT</discovery_protection_kind> 14 <liveliness_protection_kind>ENCRYPT</liveliness_protection_kind> 15 <rtps_protection_kind>ENCRYPT</rtps_protection_kind> 16 <topic_access_rules> 17 <topic_rule> 18 <topic_expression>HelloWorldTopic</topic_expression> 19 <enable_discovery_protection>true</enable_discovery_protection> 20 <enable_liveliness_protection>false</enable_liveliness_protection> 21 <enable_read_access_control>true</enable_read_access_control> 22 <enable_write_access_control>true</enable_write_access_control> 23 <metadata_protection_kind>ENCRYPT</metadata_protection_kind> 24 <data_protection_kind>ENCRYPT</data_protection_kind> 25 </topic_rule> 26 </topic_access_rules> 27 </domain_rule> 28 </domain_access_rules> 29</dds>
-
对 DomainParticipant 的权限进行细分定制,包括当前 participant 对各 Topic 的“订阅权限”,“发送权限”;
<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:noNamespaceSchemaLocation="http://www.omg.org/xxx"> 3 <permissions> 4 <grant name="PublisherPermissions"> 5 <subject_name>emailAddress=xxx</subject_name> 6 <validity> 7 <not_before>2013-06-01T13:00:00</not_before> 8 <not_after>2038-06-01T13:00:00</not_after> 9 </validity> 10 <allow_rule> 11 <domains> 12 <id_range> 13 <min>0</min> 14 <max>230</max> 15 </id_range> 16 </domains> 17 <publish> 18 <topics> 19 <topic>HelloWorldTopic</topic> 20 </topics> 21 </publish> 22 </allow_rule> 23 <default>DENY</default> 24 </grant> 46 </permissions> 47</dds>
数据加密
-
提供的能力
提供加解密相关工具,封装加解密,Hash,密钥生成,签名验证等能力;默认使用 AES-GCM-128 加密方式,以及 GMAC 消息验证码;
本插件需要和“身份鉴定”以及“访问控制”插件配合使用;
-
配置
emplace_back("dds.sec.crypto.plugin", "builtin.AES-GCM-GMAC");
安全日志
记录上述所有的涉及安全的事件日志,方便安全行为分析,以及错误分析;
Level | Definition |
---|---|
EMERGENCY_LEVEL | System is unusable. Should not continue use. |
ALERT_LEVEL | Should be corrected immediately. |
CRITICAL_LEVEL | A failure in primary application. |
ERROR_LEVEL | General error conditions. Default value. |
WARNING_LEVEL | May indicate future error if action not taken. |
NOTICE_LEVEL | Unusual, but nor erroneous event or condition. |
INFORMATIONAL_LEVEL | Normal operational. Requires no action. |
DEBUG_LEVEL | Normal operational. |
-
日志配置
DomainParticipantQos pqos; pqos.properties().properties().emplace_back("dds.sec.log.plugin", "builtin.DDS_LogTopic"); pqos.properties().properties().emplace_back( "dds.sec.log.builtin.DDS_LogTopic.logging_level", "EMERGENCY_LEVEL"); pqos.properties().properties().emplace_back( "dds.sec.log.builtin.DDS_LogTopic.log_file", "myLogFile.log");
数据标签
数据标签插件在 FastDDS 中还未实现,未来会有实现可用;
动态数据类型
动态数据类型 提供动态的方式定义 Topic 以及 TopicData,而不用提前定义 IDLs,对一些动态要求较高的场景下比较合适;
详细文档: Extensible and Dynamic Topic Types for DDS
相关依赖
库 | 简介 |
---|---|
Asio | 用于网络和低级 I/O 编程的跨平台 C++ 库,它使用现代 C++ 方法为开发人员提供一致的异步模型。 |
TinyXML2 | 开源、简单、小巧、高效的C++ XML解析器,它只有一个.h文件和一个.cpp文件组成。 |
OpenSSL | |
Foonathan memory | 内存分配器 |
Fast CDR | FastDDS 使用的高效序列化库; 性能比较: Apache Thrift vs Protocol Buffers vs Fast Buffers |
Fast DDS-Gen | 一个 Java 应用程序,它根据接口描述语言 (IDL) 文件中定义的数据类型自动生成 C++ 源代码。 |
参考
- DDS与FastRTPS
- Using DDS with TSN and Adaptive AUTOSAR
- Data Distribution Service™ (DDS™)
- ROS 2设计文章系列之十一——ROS 2与DDS-Security的集成
- 基于安全协商的DDS安全通信中间件设计
- 工业级数据分发服务DDS简介及安全特性分析
- OpenSSL生成根证书CA及签发子证书
- DDS Security v1.1
- IGMP
- IGMP基础原理与实验
IOT(物联网)的七大通信协议
目录
TCP/IP协议与Http协议的区别
TPC/IP协议是传输层协议,主要解决数据如何在网络中传输.
HTTP是应用层协议,主要解决如何包装数据.
关于TCP/IP和HTTP协议的关系,网络有一段比较容易理解的介绍:“我们在传输数据时,可以只使用(传输层)TCP/IP协议,但是那样的话,如果没有应用层,便无法识别数据内容,如果想要使传输的数据有意义,则必须使用到应用层协议,应用层协议有很多,比如HTTP、FTP、TELNET等,也可以自己定义应用层协议。WEB使用HTTP协议作应用层协议,以封装HTTP 文本信息,然后使用TCP/IP做传输层协议将它发到网络上。”
术语TCP/IP代表传输控制协议/网际协议,指的是一系列协议。“IP”代表网际协议,TCP和UDP使用该协议从一个网络传送数据包到另一个网络。把IP想像成一种高速公路,它允许其它协议在上面行驶并找到到其它电脑的出口。TCP和UDP是高速公路上的“卡车”,它们携带的货物就是像HTTP,文件传输协议FTP这样的协议等。
你应该能理解,TCP和UDP是FTP,HTTP和SMTP之类使用的传输层协议。虽然TCP和UDP都是用来传输其他协议的,它们却有一个显著的不同:TCP提供有保证的数据传输,而UDP不提供。这意味着TCP有一个特殊的机制来确保数据安全的不出错的从一个端点传到另一个端点,而UDP不提供任何这样的保证。
HTTP(超文本传输协议)是利用TCP在两台电脑(通常是Web服务器和客户端)之间传输信息的协议。客户端使用Web浏览器发起HTTP请求给Web服务器,Web服务器发送被请求的信息给客户端。
物联网协议
一类是传输协议,一类是通信协议。
- 传输协议一般负责子网内设备间的组网及通信;
- 通信协议则主要是运行在传统互联网TCP/IP协议之上的设备通讯协议,负责设备通过互联网进行数据交换及通信。
物联网的通信环境有Ethernet, Wi-Fi, RFID, NFC(近距离无线通信), Zigbee, 6LoWPAN(IPV6低速无线版本),Bluetooth, GSM, GPRS, GPS, 3G, 4G等网络,而每一种通信应用协议都有一定适用范围。AMQP、JMS、REST/HTTP都是工作在以太网,COAP协议是专门为资源受限设备开发的协议,而DDS和MQTT的兼容性则强很多。
互联网时代,TCP/IP协议已经一统江湖,现在的物联网的通信架构也是构建在传统互联网基础架构之上。在当前的互联网通信协议中
HTTP协议由于开发成本低,开放程度高,几乎占据大半江山,所以很多厂商在构建物联网系统时也基于http协议进行开发。包括google主导的physic web项目,都是期望在传统web技术基础上构建物联网协议标准。
HTTP协议是典型的C/S通讯模式,由客户端主动发起连接,向服务器请求XML或JSON数据。该协议最早是为了适用web浏览器的上网浏览场景和设计的,目前在PC、手机、pad等终端上都应用广泛,但并不适用于物联网场景。在物联网场景中其有三大弊端:
(1) 由于必须由设备主动向服务器发送数据,难以主动向设备推送数据。对于单单的数据采集等场景还勉强适用,但是对于频繁的操控场景,只能推过设备定期主动拉取的的方式,实现成本和实时性都大打折扣。(物联网设备性能不行,便宜)
(2) 安全性不高。web的不安全都是妇孺皆知,HTTP是明文协议,在很多要求高安全性的物联网场景,如果不做很多安全准备工作(如采用https等),后果不堪设想。
(3) 不同于用户交互终端如pc、手机,物联网场景中的设备多样化,对于运算和存储资源都十分受限的设备,http协议实现、XML/JSON数据格式的解析,都是不可能的任务。
IOT的七大通信协议:
1. REST/HTTP(松耦合服务调用)
REST即表述性状态传递,是基于HTTP协议开发的一种通信风格。
适用范围:
REST/HTTP主要为了简化互联网中的系统架构,快速实现客户端和服务器之间交互的松耦合,降低了客户端和服务器之间的交互延迟。因此适合在物联网的应用层面,通过REST开放物联网中资源,实现服务被其他应用所调用。
特点:
(1)REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是RESTful。
(2)客户端和服务器之间的交互在请求之间是无状态的。
(3)在服务器端,应用程序状态和功能可以分为各种资源,它向客户端公开,每个资源都使用 URI 得到一个唯一的地址。所有资源都共享统一的界面,以便在客户端和服务器之间传输状态。
(4)使用的是标准的 HTTP 方法,比如:GET、PUT、POST 和 DELETE。
REST/HTTP其实是互联网中服务调用API封装风格,物联网中数据采集到物联网应用系统中,在物联网应用系统中,可以通过开放REST API的方式,把数据服务开放出去,被互联网中其他应用所调用。
2. CoAP协议
CoAP (Constrained Application Protocol),受限应用协议,应用于无线传感网中协议。
适用范围:
CoAP是简化了HTTP协议的RESTful API,CoAP是6LowPAN协议栈中的应用层协议,它适用于在资源受限的通信的IP网络。
特点:
(1)报头压缩:CoAP包含一个紧凑的二进制报头和扩展报头。它只有短短的4B的基本报头,基本报头后面跟扩展选项。一个典型的请求报头为10~20B。
(2)方法和URIs:为了实现客户端访问服务器上的资源,CoAP支持GET、PUT、POST和DELETE等方法。CoAP还支持URIs,这是Web架构的主要特点。
(3)传输层使用UDP协议:CoAP协议是建立在UDP协议之上,以减少开销和支持组播功能。它也支持一个简单的停止和等待的可靠性传输机制。
(4)支持异步通信:HTTP对M2M(Machine-to-Machine)通信不适用,这是由于事务总是由客户端发起。而CoAP协议支持异步通信,这对M2M通信应用来说是常见的休眠/唤醒机制。
(5)支持资源发现:为了自主的发现和使用资源,它支持内置的资源发现格式,用于发现设备上的资源列表,或者用于设备向服务目录公告自己的资源。它支持RFC5785中的格式,在CoRE中用/.well—known/core的路径表示资源描述。
(6)支持缓存:CoAP协议支持资源描述的缓存以优化其性能。
协议主要实现:
· libcoap(C语言实现)
· Californium(java语言实现)
CoAP和6LowPan,这分别是应用层协议和网络适配层协议,其目标是解决设备直接连接到IP网络,也就是IP技术应用到设备之间、互联网与设备之间的通信需求。因为IPV6技术带来巨大寻址空间,不光解决了未来巨量设备和资源的标识问题,互联网上应用可以直接访问支持IPV6的设备,而不需要额外的网关。
3. MQTT协议(低带宽)
MQTT (Message Queuing Telemetry Transport ),消息队列遥测传输,由IBM开发的即时通讯协议,相比来说比较适合物联网场景的通讯协议。MQTT协议采用发布/订阅模式,所有的物联网终端都通过TCP连接到云端,云端通过主题的方式管理各个设备关注的通讯内容,负责将设备与设备之间消息的转发。
适用范围:
在低带宽、不可靠的网络下提供基于云平台的远程设备的数据传输和监控。
特点:
(1) 使用基于代理的发布/订阅消息模式,提供一对多的消息发布
(2) 使用 TCP/IP 提供网络连接
(3) 小型传输,开销很小(固定长度的头部是 2 字节),协议交换最小化,以降低网络流量
(4) 支持QoS,有三种消息发布服务质量:“至多一次”, “至少一次”, “只有一次”
协议主要实现和应用:
(1) 已经有PHP,JAVA,Python,C,C#等多个语言版本的协议框架
(2) IBM Bluemix 的一个重要部分是其 IoT FoundaTIon 服务,这是一项基于云的 MQTT 实例
(3) 移动应用程序也早就开始使用MQTT,如 Facebook Messenger 和com等
MQTT协议一般适用于设备数据采集到端(Device-》Server,Device-》Gateway),集中星型网络架构(hub-and-spoke),不适用设备与设备之间通信,设备控制能力弱,另外实时性较差,一般都在秒级。
4. DDS协议(高可靠性、实时)
DDS(Data Distribution Service for Real-Time Systems),面向实时系统的数据分布服务。
适用范围:
分布式高可靠性、实时传输设备数据通信。目前DDS已经广泛应用于国防、民航、工业控制等领域。
特点:
(1) 以数据为中心
(2) 使用无代理的发布/订阅消息模式,点对点、点对多、多对多
(3) 提供多大21种QoS服务质量策略
协议主要实现:
· OpenDDS 是一个开源的 C++ 实现
· OpenSplice DDS
DDS很好地支持设备之间的数据分发和设备控制,设备和云端的数据传输,同时DDS的数据分发的实时效率非常高,能做到秒级内同时分发百万条消息到众多设备。DDS在服务质量(QoS)上提供非常多的保障途径,这也是它适用于国防军事、工业控制这些高可靠性、可安全性应用领域的原因。但这些应用都工作在有线网络下,在无线网络,特别是资源受限的情况下,没有见到过实施案例。
5. AMQP协议(互操作性)
AMQP(Advanced Message Queuing Protocol),先进消息队列协议,用于业务系统例如PLM,ERP,MES等进行数据交换。
适用范围:
最早应用于金融系统之间的交易消息传递,在物联网应用中,主要适用于移动手持设备与后台数据中心的通信和分析。
特点:
(1) Wire级的协议,它描述了在网络上传输的数据的格式,以字节为流
(2) 面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全
协议实现:
· Erlang中的实现有 RabbitMQ
· AMQP的开源实现,用C语言编写OpenAMQ
· Apache Qpid
· stormMQ
6. XMPP协议(即时通信)
XMPP(Extensible Messaging and Presence Protocol)可扩展通讯和表示协议,一个开源形式组织产生的网络即时通信协议。
适用范围:
即时通信的应用程序,还能用在网络管理、游戏、远端系统监控等。
特点:
(1) 客户机/服务器通信模式
(2) 分布式网络
(3) 简单的客户端,将大多数工作放在服务器端进行
(4) 标准通用标记语言的子集XML的数据格式
XMPP是基于XML的协议,由于其开放性和易用性,在互联网及时通讯应用中运用广泛。相对HTTP,XMPP在通讯的业务流程上是更适合物联网系统的,开发者不用花太多心思去解决设备通讯时的业务通讯流程,相对开发成本会更低。但是HTTP协议中的安全性以及计算资源消耗的硬伤并没有得到本质的解决。
7. JMS
JMS (Java Message Service),即消息服务,这是JAVA平台中著名的消息队列协议。
Java消息服务应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。Java消息服务是一个与具体平台无关的API,绝大多数MOM提供商都对JMS提供支持。
JMS是一种与厂商无关的 API,用来访问消息收发系统消息,它类似于JDBC(Java Database Connectivity)。这里,JDBC 是可以用来访问许多不同关系数据库的 API,而 JMS 则提供同样与厂商无关的访问方法,以访问消息收发服务。许多厂商都支持 JMS,包括 IBM 的 MQSeries、BEA的 Weblogic JMS service和 Progress 的 SonicMQ。 JMS 能够通过消息收发服务(有时称为消息中介程序或路由器)从一个 JMS 客户机向另一个 JMS客户机发送消息。消息是 JMS 中的一种类型对象,由两部分组成:报头和消息主体。报头由路由信息以及有关该消息的元数据组成。消息主体则携带着应用程序的数据或有效负载。根据有效负载的类型来划分,可以将消息分为几种类型,它们分别携带:简单文本(TextMessage)、可序列化的对象 (ObjectMessage)、属性集合 (MapMessage)、字节流 (BytesMessage)、原始值流 (StreamMessage),还有无有效负载的消息 (Message)。
协议对比:
协议应用的侧重方向
MQTT、 DDS、 AMQP、XMPP、 JMS、 REST、 CoAP这几种协议都已被广泛应用,并且每种协议都有至少10种以上的代码实现,都宣称支持实时的发布/订阅的物联网协议,但是在具体物联网系统架构设计时,需考虑实际场景的通信需求,选择合适的协议。
以智能家居为例,说明下这些协议侧重应用方向。智能家居中智能灯光控制,可以使用XMPP协议控制灯的开关;智能家居的电力供给,发电厂的发动机组的监控可以使用DDS协议;当电力输送到千家万户时,电力线的巡查和维护,可以使用MQTT协议;家里的所有电器的电量消耗,可以使用AMQP协议,传输到云端或家庭网关中进行分析;最后用户想把自家的能耗查询服务公布到互联网上,那么可以使用REST/HTTP来开放API服务。
物联网协议的选择
发布/订阅服务更适合物联网环境下通信
DDS、MQTT、AMQP和JMS都是基于发布/订阅模式,发布/订阅框架具有服务自发现、动态扩展、事件过滤的特点,它解决了物联网系统在应用层的数据源快速获取、物的加入和退出、兴趣订阅、降低带宽流量等问题,实现物的联接在空间上松耦合(双方无需知道通信地址)、时间上松耦合和同步松耦合。
服务质量(QoS)是物联网通信中的重要考虑因素
在服务策略的帮助下,DDS能够有效地控制和管理网络带宽、内存空间等资源的使用,同时也能控制数据的可靠性、实时性和数据的生存时间,通过灵活使用这些服务质量策略,DDS不仅能在窄带的无线环境上,也能在宽带的有线通信环境上开发出满足实时性需求的数据分发系统。
以上是关于DDS通信协议与安全实践的主要内容,如果未能解决你的问题,请参考以下文章