[CommonAPI + vsomeip]通信 客户端 5

实现了服务端,再实现一个客户端

客户端通过绑定状态改变回调去获取服务端的值改变

1、客户端

HelloWorldClient.hpp

cpp 复制代码
#ifndef HELLOWORLDCLIENT_HPP
#define HELLOWORLDCLIENT_HPP

#include <iostream>
#include <string>
#include <thread>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <functional>
#include <memory>

// 包含 CommonAPI 运行时头文件
#include <CommonAPI/CommonAPI.hpp>
#include "v1/shanghai/jiading/helloworldProxy.hpp"

using namespace v1::shanghai::jiading;

class HelloWorldClient
{
public:
    HelloWorldClient();
    ~HelloWorldClient();

    bool connectToService();
    void run();

    std::string getMessageString(uint8_t messageId);

    uint8_t getCurrentMessageId() const
    {
        return currentMessageId_;
    }
    uint8_t getCurrentEnableGreeting() const
    {
        return currentEnableGreeting_;
    }

private:
    void onMessageIdChanged(const uint8_t& value);
    void onEnableGreetingChanged(const uint8_t& value);
    void onServiceStatusChanged(CommonAPI::AvailabilityStatus status);
    void getCurrentValues();

    std::shared_ptr<CommonAPI::Runtime> runtime_;
    std::shared_ptr<helloworldProxy<>>  proxy_;

    std::atomic<bool>    serviceAvailable_;
    std::atomic<uint8_t> currentMessageId_;
    std::atomic<uint8_t> currentEnableGreeting_;

    std::thread       clientThread_;
    std::atomic<bool> running_;

    std::mutex              mutex_;
    std::condition_variable cv_;
};

#endif  // HELLOWORLDCLIENT_HPP

HelloWorldClient.cpp

cpp 复制代码
#include "HelloWorldClient.hpp"

HelloWorldClient::HelloWorldClient() : serviceAvailable_(false), currentMessageId_(0), currentEnableGreeting_(0), running_(true)
{
    std::cout << "HelloWorldClient created!" << std::endl;
}

HelloWorldClient::~HelloWorldClient()
{
    running_ = false;
    if (clientThread_.joinable())
    {
        clientThread_.join();
    }
    std::cout << "HelloWorldClient destroyed!" << std::endl;
}

bool HelloWorldClient::connectToService()
{
    runtime_ = CommonAPI::Runtime::get();
    if (!runtime_)
    {
        std::cerr << "[Client] Failed to get CommonAPI runtime!" << std::endl;
        return false;
    }

    const std::string domain     = "local";
    const std::string instance   = "shanghai.jiading.helloworld";
    const std::string connection = "client-sample";

    // 正确的模板参数用法
    proxy_ = runtime_->buildProxy<helloworldProxy>(domain, instance, connection);

    if (!proxy_)
    {
        std::cerr << "[Client] Failed to build proxy!" << std::endl;
        return false;
    }

    // 订阅属性变化
    proxy_->getMessageIdAttribute().getChangedEvent().subscribe(std::bind(&HelloWorldClient::onMessageIdChanged, this, std::placeholders::_1));

    proxy_->getEnableGreetingAttribute().getChangedEvent().subscribe(std::bind(&HelloWorldClient::onEnableGreetingChanged, this, std::placeholders::_1));

    // 订阅服务状态变化
    proxy_->getProxyStatusEvent().subscribe(std::bind(&HelloWorldClient::onServiceStatusChanged, this, std::placeholders::_1));

    std::cout << "[Client] Waiting for service to become available..." << std::endl;

    // 等待服务可用
    std::unique_lock<std::mutex> lock(mutex_);
    cv_.wait_for(lock, std::chrono::seconds(10), [this]() { return serviceAvailable_.load(); });

    return serviceAvailable_.load();
}

void HelloWorldClient::onMessageIdChanged(const uint8_t& value)
{
    currentMessageId_ = value;
    std::cout << "[Client] messageId changed to: " << (int)value << " (" << getMessageString(value) << ")" << std::endl;
}

void HelloWorldClient::onEnableGreetingChanged(const uint8_t& value)
{
    currentEnableGreeting_ = value;
    std::cout << "[Client] enableGreeting changed to: " << (int)value << " (" << (value ? "Enabled" : "Disabled") << ")" << std::endl;

    if (value)
    {
        std::cout << "[Client] Greeting is now: " << getMessageString(currentMessageId_) << std::endl;
    }
}

void HelloWorldClient::onServiceStatusChanged(CommonAPI::AvailabilityStatus status)
{
    std::cout << "[Client] Service status changed: " << (status == CommonAPI::AvailabilityStatus::AVAILABLE ? "AVAILABLE" : "NOT_AVAILABLE") << std::endl;

    if (status == CommonAPI::AvailabilityStatus::AVAILABLE)
    {
        serviceAvailable_ = true;
        cv_.notify_all();

        // 初始获取值
        getCurrentValues();
    }
    else
    {
        serviceAvailable_ = false;
    }
}

void HelloWorldClient::getCurrentValues()
{
    if (!serviceAvailable_)
    {
        std::cout << "[Client] Service not available!" << std::endl;
        return;
    }

    CommonAPI::CallStatus callStatus;
    uint8_t               messageId, enableGreeting;

    proxy_->getMessageIdAttribute().getValue(callStatus, messageId);
    if (callStatus == CommonAPI::CallStatus::SUCCESS)
    {
        std::cout << "[Client] Current messageId: " << (int)messageId << " (" << getMessageString(messageId) << ")" << std::endl;
        currentMessageId_ = messageId;
    }

    proxy_->getEnableGreetingAttribute().getValue(callStatus, enableGreeting);
    if (callStatus == CommonAPI::CallStatus::SUCCESS)
    {
        std::cout << "[Client] Current enableGreeting: " << (int)enableGreeting << " (" << (enableGreeting ? "Enabled" : "Disabled") << ")" << std::endl;
        currentEnableGreeting_ = enableGreeting;
    }
}

std::string HelloWorldClient::getMessageString(uint8_t messageId)
{
    switch (messageId)
    {
        case 0:
            return "Hello";
        case 1:
            return "World";
        case 2:
            return "Hello World";
        default:
            return "Unknown";
    }
}

void HelloWorldClient::run()
{
    if (!connectToService())
    {
        std::cerr << "[Client] Failed to connect to service!" << std::endl;
        return;
    }

    clientThread_ = std::thread([this]() {
        int counter = 0;
        while (running_)
        {
            std::this_thread::sleep_for(std::chrono::seconds(5));

            if (serviceAvailable_)
            {
                // 只打印当前状态,不尝试设置值
                std::cout << "[Client] Status check #" << counter++ << ": messageId=" << (int)currentMessageId_ << " (" << getMessageString(currentMessageId_) << ")"
                          << ", enableGreeting=" << (int)currentEnableGreeting_ << " (" << (currentEnableGreeting_ ? "Enabled" : "Disabled") << ")" << std::endl;
            }
            else
            {
                std::cout << "[Client] Service not available, waiting..." << std::endl;
            }
        }
    });
}

2、主函数 main.cpp

cpp 复制代码
#include <iostream>
#include <string>
#include <signal.h>
#include <CommonAPI/CommonAPI.hpp>
#include "server/HelloWorldService.hpp"
#include "client/HelloWorldClient.hpp"

std::shared_ptr<HelloWorldService> g_service;
std::shared_ptr<HelloWorldClient>  g_client;

void signalHandler(int signal)
{
    std::cout << "\nReceived signal " << signal << ", shutting down..." << std::endl;
    if (g_service)
        g_service.reset();
    if (g_client)
        g_client.reset();
    exit(0);
}

int main(int argc, char** argv)
{
    // 注册信号处理器
    signal(SIGINT, signalHandler);
    signal(SIGTERM, signalHandler);

    if (argc < 2)
    {
        std::cerr << "Usage: " << argv[0] << " <server|client>" << std::endl;
        return 1;
    }

    std::string mode = argv[1];

    if (mode == "server")
    {
        std::cout << "Starting HelloWorld Server..." << std::endl;

        // 创建服务
        g_service = std::make_shared<HelloWorldService>();

        // 注册服务
        std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::get();
        if (!runtime)
        {
            std::cerr << "Failed to get CommonAPI runtime!" << std::endl;
            return 1;
        }

        std::string domain     = "local";
        std::string instance   = "shanghai.jiading.helloworld";
        std::string connection = "service-sample";

        bool serviceRegistered = runtime->registerService(domain, instance, g_service, connection);

        if (!serviceRegistered)
        {
            std::cerr << "Failed to register service!" << std::endl;
            return 1;
        }

        std::cout << "Service registered successfully!" << std::endl;
        std::cout << "Domain: " << domain << std::endl;
        std::cout << "Instance: " << instance << std::endl;

        // 启动服务
        g_service->startService();

        std::cout << "Server is running. Press Ctrl+C to stop." << std::endl;

        // 保持主线程运行
        while (true)
        {
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
    else if (mode == "client")
    {
        std::cout << "Starting HelloWorld Client..." << std::endl;

        // 创建客户端
        g_client = std::make_shared<HelloWorldClient>();

        // 运行客户端
        g_client->run();

        std::cout << "Client is running. Press Ctrl+C to stop." << std::endl;

        // 保持主线程运行
        while (true)
        {
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
    else
    {
        std::cerr << "Invalid mode. Use 'server' or 'client'" << std::endl;
        return 1;
    }

    return 0;
}

通过参数区分server和client的不同代码

3、CMakeLists.txt

XML 复制代码
cmake_minimum_required(VERSION 3.10)
project(HelloWorldCommonAPI)

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 设置目标系统根目录
set(TARGET_ROOT "/home/qhr/Downloads/CommonApi_Someip/lib_deps")
message(STATUS "目标系统根目录: ${TARGET_ROOT}")

# 设置 CMake 模块路径
list(APPEND CMAKE_PREFIX_PATH
    # /usr/lib/
    ${TARGET_ROOT}
    ${TARGET_ROOT}/lib/cmake
)

# 查找 CommonAPI 和 vsomeip
find_package(CommonAPI REQUIRED)
find_package(vsomeip3 REQUIRED)
find_package(CommonAPI-SomeIP REQUIRED)

# 手动设置库文件
set(COMMONAPI_LIBRARIES "${TARGET_ROOT}/lib/libCommonAPI.so")
set(COMMONAPI_SOMEIP_LIBRARIES "${TARGET_ROOT}/lib/libCommonAPI-SomeIP.so")
set(VSOMEIP_LIBRARIES "${TARGET_ROOT}/lib/libvsomeip3.so")

message(STATUS "CommonAPI found: ${CommonAPI_FOUND}")
message(STATUS "vsomeip3 found: ${vsomeip3_FOUND}")
message(STATUS "CommonAPI-SomeIP found: ${CommonAPI-SomeIP_FOUND}")

# 包含生成的代码目录
set(VSOMEIP_INCLUDE_DIRS "${TARGET_ROOT}/include/vsomeip")

include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${COMMONAPI_INCLUDE_DIRS})
include_directories(${VSOMEIP_INCLUDE_DIRS})

message(STATUS "CMAKE_CURRENT_BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}")
message(STATUS "COMMONAPI_INCLUDE_DIRS: ${COMMONAPI_INCLUDE_DIRS}")
message(STATUS "VSOMEIP_INCLUDE_DIRS: ${VSOMEIP_INCLUDE_DIRS}")

# 收集所有生成的源文件
file(GLOB_RECURSE GENERATED_CORE_SOURCES 
    "${CMAKE_CURRENT_SOURCE_DIR}/src/common_api/core/v1/shanghai/jiading/*.cpp"
)
file(GLOB_RECURSE GENERATED_SOMEIP_SOURCES 
    "${CMAKE_CURRENT_SOURCE_DIR}/src/common_api/someip/v1/shanghai/jiading/*.cpp"
)

# 合并所有生成的源文件
set(GENERATED_SOURCES
    ${GENERATED_CORE_SOURCES}
    ${GENERATED_SOMEIP_SOURCES}
)

# 源文件
set(SERVER_SOURCES
    src/server/HelloWorldService.cpp
)

set(CLIENT_SOURCES
    src/client/HelloWorldClient.cpp
)

set(MAIN_SOURCE
    src/main.cpp
)

# # 包含目录
# include_directories(
#     ${CMAKE_CURRENT_SOURCE_DIR}/src
#     ${CMAKE_CURRENT_SOURCE_DIR}/src/server
#     ${CMAKE_CURRENT_SOURCE_DIR}/src/client
#     ${CMAKE_CURRENT_SOURCE_DIR}/common_api/core
#     ${CMAKE_CURRENT_SOURCE_DIR}/common_api/someip
#     ${COMMONAPI_INCLUDE_DIRS}
#     ${VSOMEIP3_INCLUDE_DIRS}
#     ${COMMONAPI_SOMEIP_INCLUDE_DIRS}
# )

# 创建可执行文件
add_executable(helloworld
    ${MAIN_SOURCE}
    ${SERVER_SOURCES}
    ${CLIENT_SOURCES}
    ${GENERATED_SOURCES}
)

target_include_directories(helloworld PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}/src
    ${CMAKE_CURRENT_SOURCE_DIR}/src/server
    ${CMAKE_CURRENT_SOURCE_DIR}/src/client
    ${CMAKE_CURRENT_SOURCE_DIR}/src/common_api/core
    ${CMAKE_CURRENT_SOURCE_DIR}/src/common_api/someip
    ${COMMONAPI_INCLUDE_DIRS}
    ${VSOMEIP_INCLUDE_DIRS}
    ${COMMONAPI_SOMEIP_INCLUDE_DIRS}
)

# 链接库
target_link_libraries(helloworld
    ${COMMONAPI_LIBRARIES}
    ${VSOMEIP_LIBRARIES}
    ${COMMONAPI_SOMEIP_LIBRARIES}
    pthread
)

# 复制配置文件到构建目录
configure_file(config/vsomeip_server.json ${CMAKE_CURRENT_BINARY_DIR}/vsomeip_server.json COPYONLY)
configure_file(config/vsomeip_client.json ${CMAKE_CURRENT_BINARY_DIR}/vsomeip_client.json COPYONLY)
configure_file(run_client.sh ${CMAKE_CURRENT_BINARY_DIR}/run_client.sh COPYONLY)
configure_file(run_server.sh ${CMAKE_CURRENT_BINARY_DIR}/run_server.sh COPYONLY)

# 安装目标
install(TARGETS helloworld DESTINATION bin)
install(FILES config/vsomeip_server.json config/vsomeip_client.json DESTINATION share/config)

4、启动脚本

run_client.sh

bash 复制代码
#!/bin/bash

# cd build

# 设置 VSOMEIP_CONFIGURATION 环境变量
export VSOMEIP_CONFIGURATION=vsomeip_client.json
export VSOMEIP_APPLICATION_NAME=helloworld-client
export LD_LIBRARY_PATH=/home/qhr/Downloads/CommonApi_Someip/lib_deps/lib:$LD_LIBRARY_PATH

# 启动客户端
./helloworld client

run_server.sh

bash 复制代码
#!/bin/bash

# cd build

# 设置 VSOMEIP_CONFIGURATION 环境变量
export VSOMEIP_CONFIGURATION=vsomeip_server.json
export VSOMEIP_APPLICATION_NAME=helloworld-server
export LD_LIBRARY_PATH=/home/qhr/Downloads/CommonApi_Someip/lib_deps/lib:$LD_LIBRARY_PATH

# 启动服务端
./helloworld server

5、编译

bash 复制代码
mkdir build
cd build/
cmake ..
make

生成产物如上

6、运行

打开两个终端,先启动server

bash 复制代码
./run_server.sh

在启动client

bash 复制代码
./run_client.sh

至此demo结束

7、后续

后续在实际项目中需要考虑这套东西的运行效率,有someip原生接口效率低?低多少?

相关推荐
小鸡吃米…2 小时前
机器学习 - 精确率与召回率
人工智能·python·机器学习
学步_技术2 小时前
多模态学习—A Survey of Multimodal Learning: Methods, Applications, and Future
人工智能·深度学习·计算机视觉
智算菩萨2 小时前
2026年2月AI大语言模型评测全景:GPT-5.2与Claude 4.5的巅峰对决及国产模型崛起之路
人工智能·ai编程·ai写作
阿杰学AI2 小时前
AI核心知识79——大语言模型之Knowledge Conflict(简洁且通俗易懂版)
人工智能·ai·语言模型·自然语言处理·aigc·rag·知识冲突
极客小云2 小时前
【YOLO26教育版目标检测项目详解 - 从零开始掌握YOLO核心原理】
人工智能·yolo·目标检测
ar01232 小时前
可视化AR巡检:工业智能化发展的新引擎
人工智能·ar
星火开发设计2 小时前
C++ 输入输出流:cin 与 cout 的基础用法
java·开发语言·c++·学习·算法·编程·知识
沫儿笙2 小时前
库卡机器人厚板焊接节气设备
网络·人工智能·机器人
2501_933329552 小时前
Infoseek数字公关AI中台:基于深度学习的全链路智能舆情处置系统架构解析与实战应用
人工智能·深度学习·系统架构