SOA相对于dds的主要区别是SOA引入了服务和服务实例的概念这就导致以下几点1、SOA规范服务发现怎么实现2、dds中DomainParticipant、DataWriter、DataReader怎么和SOA中的服务、骨架、代理对应3、通信的struct怎么实现主要要考虑实例idSOA是面向服务的通信架构DDS属于DOA面向数据的通信架构。SOA即面向服务架构。虽然一开始我们对SOA面向服务架构的概念不了解感觉很抽象。但是当看到面向xxx的时候是很熟悉的讨论c时说c是面向对象的编程语言。面相对象那么对象作为一个基础的、核心的的概念是c的核心c中的概念都围绕着对象展开类、抽象类、封装、继承、多态、模板等。那么对于SOA架构来说则所有的概念都围绕着服务展开。AP AUTOSAR标准基于SOA范式实现了通信模块(Specification of Communication Management)实现了面向服务的通信SOC(Service-Oriented Communication)。本文以AP AUTOSAR2311通信规范文档为依据来讨论面向服务通信。1SOC基本概念本文中服务端、骨架端是同一个概念客户端代理端是同一个概念。面向服务通信即通过服务这个基本概念把通信的概念涵盖进来。在自动驾驶中间件领域即使我们完全没有听说过SOA的概念当我们开发通信中间件的时候不管使用dds还是ZMQ还是其它的通信中间件我们常常要对中间件接口进行封装实现如下的功能1发布-订阅一侧发布数据一侧订阅数据比如原生dds就支持这种语义。2远程调用远程调用可以像调用本地函数那样调用远程的函数可以有入参和返回值。也可以像setter和getter类似的功能远程设置一个属性或者获取一个属性。SOC通过服务这个核心概念把我们常用的一些通信范式进行了统一把常用的通信范式囊括了进来。SOC通过服务来提供发布-订阅、远程调用功能。当我们看到SOC的时候完全不必纠结于面向服务到底是个什么概念为什么叫面向服务我们只需要知道面向服务通过服务这个核心概念将发布-订阅、远程调用这些我们常见的通信范式进行了统一即可。服务服务是核心概念SOC中的所有概念都围绕着服务来展开。如上图所示表示SOC的基本示意图有服务的提供者服务的需求者。服务的提供者提供服务offer服务的需求者查找服务find需求者找到服务之后便可以使用这个服务。服务实例对于同一个服务可以有一个服务端也可以有多个服务端。每个服务端都是一个服务实例服务实例用一个uint16类型的数据表示叫做实例id。对于同一个服务可以有多个服务实例来提供这个服务。客户端可以通过实例id来查找并使用对应的服务。客户端可以指定一个要发现的服务也可以指定发现该服务下的所有实例。服务实例用于区分不同的服务端不能用来区分客户端。SOA规范中也没有规定怎么区分不同的客户端。骨架和代理骨架又称为服务端代理又称为客户端类似于tcp/udp的服务端和客户端。服务端提供服务客户端使用服务。event:event是发布订阅的通信范式。在SOC中只能服务端发布数据客户端订阅数据不能反过来。trigger:简化版的event没有具体数据。类似于进程间通信的socket和信号量socket可以传输具体的数据信号量只是负责将线程唤醒。event类似于socket trigger类似于信号量。服务端发送trigger客户端接收trigger。method:method即方法在c或者java中类中声明的函数一般也叫方法。SOC里的方法和c类中的方法概念是类似的都是调用一个函数有形参和返回值区别是c中的方法是本地调用SOC是远程调用。服务端作为方法的提供者客户端可以调用。field:field即字段。在c中当我们定义一个类的属性常常把属性定义为private如果有在类外部访问这个属性的需求比如读和写那么便会声明对应的setter、getter方法。SOC中的field与c类中的setter、getter类似可以通过setter和getter远程设置或读取该字段的值。2基于dds实现SOCAP com提供了两种服务发现机制一种是基于UserDataQos一种是基于topic。2.1服务发现服务发现是通信的前提不管是event、method、field、trigger哪种通信方式只有发现服务才能够进行具体的通信。dds本身也有服务发现的机制要经过PDP、EDP两个阶段进行服务发现PDP是participant之间的相互发现EDP是data writer和data reader之间的相互发现。dds的服务发现过程不需要用户参与不需要用户调用什么接口用户如果关心发现事件那么可以通过dds提供的回调函数来监听。SOC不同需要用户明确地调用接口来提供服务和查找服务用户要参与到服务发现的过程中去服务端要提供服务只有提供服务之后客户端才可以发现服务客户端要查找服务查找到服务之后要设置接收数据的回调函数只能接收已查找到的服务。SOA提供了OffserService,StopOfferService,StartFindService,StopFindService等接口用户可以对服务发现过程进行精确控制。服务id也就是服务的名字服务实例id服务的版本号。这3的元素3元组用来描述一个服务。offer服务的时候需要提供3元组信息find service的时候也需要提供这3个信息。服务发现是通过domain participant发现服务的过程。对于客户端来说只要发现了服务就么就会返回handle而不是data reader和data writer match了之后才返回handle。FindService和StartFindService前者是查找当前的快照后者是持续监督当发现有新服务或者服务退出均能被异步通知。2.1.1基于UserDataQosPolicy的服务发现UserDataQosPolicy参考fastdds qos:UserDataQosPolicy-CSDN博客用DomainPaticipant来代表一个服务实例。当服务端OfferService的时候创建对应的DomainParticiapant并为DomainParticiapant设置UserDataUserData的格式按下图所示。前缀是ara.com://services/后边是服务id服务实例id版本号。如果多个服务实例共用一个DomainParticipant那么UserData也可以设置多个服务实例的信息。客户端也应创建DomainParticiapant并当发现新的DomainParticiapant的时候读取发现的DomainParticiapant的UserData来判断该服务实例是不是自己所要找的服务实例。fastdds qos:UserDataQosPolicy-CSDN博客通过继承DomainParticipantListener当有新的participant发现时便可以获取participant的user data。服务端的domain participant设置user data客户端的domain participant不需要设置。当客户端发现domain participant时获取user data通过解析user data中的service id和instance id便可以确定服务是不是自己要找的服务。2.1.1.1PartitionQos如果服务端有两个实例id分别是1和2。客户端有两个客户端1和客户端2分别需要服务端1和服务端2那么客户端1只需要发现服务端1的DataWriter和DataReader客户端2只需要发现服务端2的DataWriter和DataReader。虽然1和2的topic相同data type也相同但是实际使用中客户端1不需要发现服务端2客户端2也不需要发现服务端1。这种使用需求可以通过PartitionQos来实现。默认情况下所有在同一个participant同一个topic下的data writer和data reader都可以相互发现PartitionQos可以对topic进行分区只有在同一个分区下的data writer和data reader才能相互发现。这种技术实现了对topic的复用类似的技术在很多场景中也有使用比如为了节省资源在tcp socket的基础上虚拟一层连接多个虚拟连接复用同一个tcp连接。客户端针对发现的每个服务实例都创建一个Publisher和SubScriberPartitionQos配置为PartitionQos。服务端服务端也需要创建一个Publisher和Subscriber并配置PartitionQos。不管是服务端还是客户端都需要针对每个服务实例创建对应的Publisher和Subscriber并设置PartitionQosPolicy。通过DomainParticipant的UserDataQosPolicy和DataWriter/DataReader下的PartitionQosPolicy实现服务发现的过程。2.1.3dds和SOC映射关系1、当服务端调用OfferService1用DomainParticipant代表一个服务实例。domain id和qos profile用来标记一个domain participant如果有相同的服务实例domain id和qos profile相同那么服务实例可以使用同一个participant。2针对每个event创建一个topic和DataWriter3针对每个trigger创建一个topic和DataWriter4针对method创建一个request topic和一个reply topic服务端要创建request topic的DataReader和reply topic的DataWriter。通过一个requect topic和reply topic实现远程调用功能。这是最简单也是最先想到的一种实现方式。在没有接触SOC标准的时候自己也能想到这样的实现方式但是总感觉这种方式不太优雅太low了。服务端创建request topic的data reader和reply topic的data writer客户端则创建request topic的data writer和reply topic的data reader。所有创建topic的地方都需要检查是不是已经创建了同一个participant如果已经创建了那么不能重复创建。5field处理①如果field中包含notifiernotifier与event类似那么需要创建一个topic和DataWriter②当hadGetter或hasSetter创建一个request topic和一个reply topic服务端要创建request topic的DataReader和reply topic的DataWriter6为Domainparticipant设置user data2、当服务端调用StopOfferService1将user data从Domainparticipant的qos中移除。将user data移除之后即使该daomin participant再被发现也不会获取到该服务的信息也就相当于停止提供服务了。2移除在OfferService时创建的DataWriter和DataReadertopic可能共享所以topic要进行判断没有使用者的时候才可以销毁。3、当客户端调用FindService、StartFindService(1)绑定一个BuiltinParticipantListener(2)查找已经发现的DomainParticipant根据客户端配置的关注的服务实例向用户返回对应服务实例的handle4、当客户端调用StopFindService解绑BuiltinParticipantListener2.1.2基于topic的服务发现机制基于topic进行服务发现则需要内部创建一个topicara.com://services/discovery该topic的data type为ServiceAnnouncementMessage。每个进程都要创建该topic以及对应的DataWriter和DataReader。ServiceAnnouncementMessage不是周期性发送那么怎么保证新上线的DataReader能发现在之前上线的DataWriter发布的服务信息呢需要按如下配置DataWriter的qos。DataWriter配置DurabilityQosPolicy为TRANSIENT_LOCAL则发送的事件会进行保存新上线的DataReader也能获取到历史数据。HISTORY的KEEP_LAST的DEPTH配置为1。每个interface_id和instance_id够成一个key来创建一个instance。当identifier type设置为SERVICE_INSTANCE_RESOURCE_TOPIC_PREFIX则服务端和客户端的Publisher和Subscriber不需要设置PartitionQos而是会通过topic名来进行分区划分。实际使用的topic名格式如下ara.com://services/InterfaceID/InstanceID/TopicName当identifier_type设置为SERVICE_INSTANCE_RESOURCE_PARTITION则需要对Publisher和Subscriber设置Partition Qos。2.2event1struct名字在用户的名字之后加了后缀EventType2struct字段增加了instance_idkey,topic instance以instance_id作为key来标记instance。2.3trigger1struct名是固定的TriggerType。不像event每个event的数据是有区别的所以每个event的struct是不一样的而trigger只是一个信号不需要包含用户信息所以trigger的struct可以固定。2struct成员只有一个即实例id2.4methodRequestHeader和ReplyHeader均是omg定义的规范https://www.omg.org/spec/DDS-RPC/1.0/PDF。RequestHeader中instanceName即服务实例的实例idrequestId是DataWriter的guid。DataWriter的guid在RequestHeader和ReplyHeader中均有当调用方法的一方收到reply之后根据DataWriter的guid来判断request是不是自己发送的如果是则将返回值返回给用户否则不返回。2.5fieldfield中的notifier与event类似只不过struct命名有区别。。setter、getter使用的data type与method类似。同样的struct命名有区别。