实现了服务端,再实现一个客户端
客户端通过绑定状态改变回调去获取服务端的值改变
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原生接口效率低?低多少?