3. 实现服务端并注册服务

实现服务端并注册服务 学习卡片

任务说明

本案例在AUTOSAR Adaptive平台上实现一个服务端,该服务端提供算术运算服务(加法与乘法),并通过ara::com的Service Registry完成服务实例注册,使客户端能够发现并调用该服务。最终交付物为一个可独立编译运行的C++源文件,包含服务接口定义、服务实现及注册逻辑。

服务接口定义

首先定义服务接口。该服务名为ArithmeticService,提供两个方法:add(输入两个int32,返回int32)和multiply(输入两个int32,返回int32)。使用AUTOSAR Adaptive的标准事件与方法模型,通过代理(Proxy)与服务端(Skeleton)模式实现通信。

// ArithmeticServiceInterface.hpp
#pragma once
#include <ara/com/types.h>
#include <ara/com/ServiceInterface.h>

namespace ara {
namespace com {
namespace sample {

// 方法输入/输出结构
struct AddInput {
    int32_t a;
    int32_t b;
};

struct AddOutput {
    int32_t result;
};

struct MultiplyInput {
    int32_t a;
    int32_t b;
};

struct MultiplyOutput {
    int32_t result;
};

// 服务接口声明
class ArithmeticServiceInterface : public ara::com::ServiceInterface {
public:
    using AddMethod = ara::com::Method<AddInput, AddOutput>;
    using MultiplyMethod = ara::com::Method<MultiplyInput, MultiplyOutput>;

    static constexpr char const* ServiceIdentifier = "ArithmeticService/1.0";
};

} // namespace sample
} // namespace com
} // namespace ara

服务端实现与注册

服务端继承Skeleton模板,实现接口中定义的方法,并在main函数中实例化服务端对象,调用OfferService()完成注册。注册后服务进入可用状态,等待客户端发现与调用。

// ArithmeticServiceServer.cpp
#include <ara/com/skeleton/Skeleton.h>
#include <ara/com/runtime.h>
#include <ara/log/log.h>
#include "ArithmeticServiceInterface.hpp"
#include <thread>
#include <chrono>

using namespace ara::com;
using namespace ara::com::sample;

class ArithmeticServiceSkeleton : public Skeleton<ArithmeticServiceInterface> {
public:
    // 构造函数:注册方法处理器
    explicit ArithmeticServiceSkeleton(ara::core::InstanceSpecifier instance)
        : Skeleton<ArithmeticServiceInterface>(instance) {
        // 绑定方法实现
        RegisterMethod(ArithmeticServiceInterface::AddMethod::Identifier,
                       [this](const AddInput& in, AddOutput& out) {
                           out.result = in.a + in.b;
                           ara::log::LogInfo() << "Add called: " << in.a << " + " << in.b << " = " << out.result;
                       });
        RegisterMethod(ArithmeticServiceInterface::MultiplyMethod::Identifier,
                       [this](const MultiplyInput& in, MultiplyOutput& out) {
                           out.result = in.a * in.b;
                           ara::log::LogInfo() << "Multiply called: " << in.a << " * " << in.b << " = " << out.result;
                       });
    }
};

int main() {
    // 初始化运行时
    ara::com::Runtime::Initialize();
    ara::log::LogInfo() << "ArithmeticService server starting...";

    // 创建服务端实例(实例ID需与manifest一致)
    ara::core::InstanceSpecifier specifier("ArithmeticService/1.0/ServerInstance");
    ArithmeticServiceSkeleton server(specifier);

    // 注册服务(使服务可被发现)
    auto offerResult = server.OfferService();
    if (!offerResult.HasValue()) {
        ara::log::LogError() << "OfferService failed: " << offerResult.Error().Message();
        return -1;
    }
    ara::log::LogInfo() << "Service offered successfully. Waiting for client calls...";

    // 保持进程运行
    while (true) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
    return 0;
}

关键实现说明

  • 方法注册:通过RegisterMethod将接口中定义的方法ID与Lambda处理器绑定,当客户端调用对应方法时,处理器被触发并返回计算结果。
  • 服务注册:OfferService()将服务实例注册到ara::com的Service Registry中,注册成功后客户端可通过服务发现机制找到该实例。
  • 实例标识:InstanceSpecifier需与部署清单(manifest)中配置的实例ID一致,否则注册会失败。

编译与运行

本代码依赖AUTOSAR Adaptive基础库(ara::com、ara::log、ara::core)。编译时需链接对应库并包含头文件路径。典型编译命令如下(以AUTOSAR Adaptive标准工具链为例):

g++ -std=c++17 -I${ARA_INCLUDE_PATH} ArithmeticServiceServer.cpp \
    -L${ARA_LIB_PATH} -lara_com -lara_log -lara_core \
    -o arithmetic_server

运行前需确保ara::com运行时环境已启动(如通过执行管理器启动),且manifest中已配置服务实例的端口与通信参数。运行服务端:

./arithmetic_server

验证方法

服务端启动后,观察日志输出。若注册成功,应看到Service offered successfully日志。随后使用配套的客户端程序(或ara::com调试工具)进行服务发现并调用add(3,4)与multiply(5,6)方法。服务端日志会打印每次调用的参数与结果,客户端应收到返回值7和30。

判定标准:服务端日志显示注册成功且无错误输出;客户端能够发现服务并成功调用两个方法,返回结果与预期一致(3+4=7,5×6=30),即判定本案例通过。

服务端注册与调用时序 服务端 ArithmeticServiceSkeleton Service Registry ara::com 服务注册表 客户端 Proxy (发现与调用) 1. OfferService() 注册服务实例 2. 注册成功 3. FindService() 按服务ID查询 4. 返回代理句柄 5. 远程方法调用 add(3,4) / multiply(5,6) 6. 返回结果 (7, 30) 验证观测点 服务端日志显示 "Service offered successfully" → 注册成功;客户端收到 add=7, multiply=30 → 调用链路正常