3. 服务发现与注册
任务说明
本案例在AUTOSAR AP(Adaptive Platform)环境中实现基于SOME/IP的服务发现(Service Discovery)机制。目标是通过ara::com标准接口完成服务提供端(Service Provider)的实例注册与客户端(Service Client)的动态发现,使客户端无需预先配置服务实例地址即可获取可用服务端点并建立通信。
实现方案
采用AUTOSAR AP的ara::com通信管理框架,利用其内置的SOME/IP Service Discovery(SD)模块。服务端通过ara::com::InstanceIdentifier标识服务实例,调用OfferService完成注册;客户端通过StartFindService异步发现服务,并在回调中获取服务句柄。该机制基于AUTOSAR AP R19-11规范,使用C++11标准实现。
代码实现
// service_discovery_demo.cpp
#include <ara/com/ServiceProxy.h>
#include <ara/com/ServiceProvider.h>
#include <ara/com/InstanceIdentifier.h>
#include <ara/com/ServiceHandle.h>
#include <ara/com/FindServiceHandle.h>
#include <ara/com/ServiceDiscovery.h>
#include <ara/core/Result.h>
#include <ara/core/InstanceSpecifier.h>
#include <iostream>
#include <thread>
#include <chrono>
#include <memory>
// 定义服务接口(示例:计算服务)
namespace calc {
constexpr ara::core::StringView kServiceName = "CalcService";
// 服务代理(客户端视角)
class CalcServiceProxy : public ara::com::ServiceProxy {
public:
explicit CalcServiceProxy(ara::com::ServiceHandle handle)
: ara::com::ServiceProxy(handle) {}
// 同步调用Add方法
ara::core::Result<int32_t> Add(int32_t a, int32_t b) {
// 实际项目中此处会生成方法调用存根
return ara::core::Result<int32_t>::FromValue(a + b);
}
};
// 服务提供(服务端视角)
class CalcServiceProvider : public ara::com::ServiceProvider {
public:
explicit CalcServiceProvider(ara::com::InstanceIdentifier instance_id)
: ara::com::ServiceProvider(instance_id) {}
void Offer() {
// 注册服务实例到SD
auto result = ara::com::ServiceDiscovery::GetInstance()->
OfferService(GetInstanceId());
if (result.HasValue()) {
std::cout << "[Provider] Service offered successfully" << std::endl;
} else {
std::cout << "[Provider] Offer failed: " << result.Error().Message() << std::endl;
}
}
void StopOffer() {
ara::com::ServiceDiscovery::GetInstance()->
StopOfferService(GetInstanceId());
std::cout << "[Provider] Service stopped" << std::endl;
}
};
}
// 服务发现回调
void OnServiceFound(ara::com::ServiceHandle handle,
ara::com::FindServiceHandle find_handle) {
std::cout << "[Client] Service discovered, instance: "
<< handle.GetInstanceId().ToString() << std::endl;
// 创建代理并调用方法
calc::CalcServiceProxy proxy(handle);
auto result = proxy.Add(3, 4);
if (result.HasValue()) {
std::cout << "[Client] Add(3,4) = " << result.Value() << std::endl;
}
// 停止继续查找(可选)
ara::com::ServiceDiscovery::GetInstance()->
StopFindService(find_handle);
}
int main() {
// 1. 初始化SD模块
ara::com::ServiceDiscovery::GetInstance()->Init();
// 2. 服务端:注册实例
ara::core::InstanceSpecifier provider_spec("/Provider/CalcService");
ara::com::InstanceIdentifier provider_id(provider_spec);
calc::CalcServiceProvider provider(provider_id);
provider.Offer();
// 3. 客户端:启动服务发现
ara::core::InstanceSpecifier client_spec("/Client/CalcService");
ara::com::InstanceIdentifier client_id(client_spec);
auto find_handle = ara::com::ServiceDiscovery::GetInstance()->
StartFindService(OnServiceFound, client_id);
// 4. 等待发现完成(实际应用中由事件驱动)
std::this_thread::sleep_for(std::chrono::seconds(2));
// 5. 清理
provider.StopOffer();
ara::com::ServiceDiscovery::GetInstance()->StopFindService(find_handle);
ara::com::ServiceDiscovery::GetInstance()->Deinit();
return 0;
}
关键机制说明
上述代码中,OfferService使服务实例在SD模块中注册,SD通过SOME/IP SD报文周期性发送Offer消息。客户端StartFindService发送FindService请求,收到Offer后触发回调OnServiceFound,其中携带服务句柄用于后续通信。服务实例标识符(InstanceIdentifier)由Manifest文件中的InstanceSpecifier映射而来,确保服务端与客户端引用同一服务。
SVG:服务发现时序图
编译与运行
# 假设AUTOSAR AP SDK已安装并设置环境变量
g++ -std=c++11 service_discovery_demo.cpp \
-o service_discovery_demo \
-lara_com -lara_core \
-I${AUTOSAR_AP_INCLUDE} -L${AUTOSAR_AP_LIB}
# 运行(需在AUTOSAR AP运行时环境中)
./service_discovery_demo
验证方法
运行程序后观察输出:服务端打印[Provider] Service offered successfully,客户端在约1秒内打印[Client] Service discovered及Add(3,4) = 7。若SD配置正确且网络可达,客户端无需任何静态IP/端口配置即可发现服务。可通过修改服务端实例标识符或断开网络验证发现失败路径,此时客户端不触发回调且无异常退出。
判定标准
- 服务端Offer后,SD模块能周期发送SOME/IP SD报文(可用Wireshark抓包验证,过滤条件
someip-sd) - 客户端StartFindService后能收到Offer并触发回调,回调中携带有效ServiceHandle
- 通过ServiceHandle可正常调用远程方法并返回正确结果
- 服务端StopOffer后,客户端在TTL过期后不再收到该服务实例的Offer