BoberClient C++ application
v1.0.0
Table of contents
- Overview
- Versions
- Library files
- Message types
- Message format
- Examples
- BoberClient class description
- Example application
- Build and connect to your project
Overview
The BoberClient is a C++ library that serves as a communication client for user applications, enabling interaction with any other service through BoberManager. It provides an interface for sending and receiving messages, managing connections, and handling acknowledgments, allowing user applications to communicate with devices, services, or other components in the system. It provides fast and robust communication protocol. Additionally BoberClient ensures proper message formatting, assigns unique IDs to outgoing messages, and validates incoming. It supports various message types: Command, Request, Notify, Response, and handles acknowledgments (Ack) and errors (Nack) automatically. The library runs a dedicated input thread to process incoming messages without blocking the main application, ensuring thread-safe access to message buffers. It also includes a ping mechanism to maintain connection status. The library is using C++17 and depends on UdpSocket library (provides methods to work with UDP sockets, source code included, Apache 2.0 license) and Logger library (provides methods to work with logs, source code included, Apache 2.0 license). Communication principle:
Versions
Table 1 - Library versions.
Version | Release date | What’s new |
---|---|---|
1.0.0 | 10.04.2025 | - First version of the library. |
Library files
The library is supplied by source code only. The user would be given a set of files in the form of a CMake project (repository). The repository structure is shown below:
CMakeLists.txt --------------- Main CMake file of the library.
3rdparty --------------------- Folder with third-party libraries.
CMakeLists.txt ----------- CMake file to include third-party libraries.
UdpSocket ---------------- Folder with UdpSocket library source code.
src -------------------------- Folder with the library source code.
CMakeLists.txt ----------- CMake file of the library.
BoberClient.cpp ---------- C++ library implementation file.
BoberClient.h ------------ Header library file.
BoberClientVersion.h ----- Header file which includes library version.
BoberClientVersion.h.in -- CMake service file to generate version header.
benchmark -------------------- Folder with benchmark application.
CMakeLists.txt ----------- CMake file of the application.
main.cpp ----------------- Source code file of benchmark application.
test ------------------------- Folder with test application.
CMakeLists.txt ----------- CMake file of the application.
main.cpp ----------------- Source code file of test application.
Message types
The BoberClient library supports different types of messages:
- Command - Used to send specific instructions or commands to another service or client. The receiver will send Ack message back if the message accepted or Nac packet if something wrong with message.
- Request - Used to request specific information or actions from another service or client. The receiver will send Response message back or Nac packet if something wrong with message.
- Response - Used to respond to a previously received Request message.
- Notify - Used to send notifications or updates to other services or clients. The receiver will send Ack message back.
- Ack - Acknowledgment message sent to confirm the successful receipt of a message. For Response there is not reply messages.
- Nack - Negative acknowledgment message sent to indicate an error or invalid message format. If the client for whom the message is intended is not in the list, the BoberManager sends the Nack message back.
Message format
The BoberClient library uses a specific message format for communication with other clients and services. The format is as follows:
[<ID>]/Src:<source>/Dst:<destination>/<type>/<content>
•
Examples:
-
Client List Request:
[121]/Src:ClientA/Dst:BoberManager/Request/Clients
• [121]: Message ID • Src:ClientA: Source client is ClientA • Dst:BoberManager: Destination is BoberManager • Request/Clients: Requesting the list of connected clients Example response:
[121]/Src:BoberManager/Dst:ClientA/Response/Clients:ClientB,ClientC
-
Request parameter message to Another Client:
[122]/Src:ClientA/Dst:ClientB/Request/Contrast
• [122]: Message ID • Src:ClientA: Source client is ClientA • Dst:ClientB: Destination client is ClientB • Request/Contrast: Requesting Contrast parameter from ClientB Example response:
[122]/Src:ClientB/Dst:ClientA/Response/Contrast:50
-
Command message to set parameter value message to Another Client:
[123]/Src:ClientA/Dst:ClientB/Command/Contrast:78
• [123]: Message ID • Src:ClientA: Source client is ClientA • Dst:ClientB: Destination client is ClientB • Command/Contrast:78: Calling command to set parameter value Example response:
[123]/Src:ClientB/Dst:ClientA/Ack
BoberClient class description
The BoberClient class provides a communication interface for user applications to interact with the BoberManager and other services in the system. It facilitates sending and receiving messages over UDP, managing connections, and handling message acknowledgments. The class abstracts the complexities of network communication, allowing integration with the broader system.
BoberClient class declaration
BoberClient interface class declared in BoberClient.h file. Class declaration:
namespace cr
{
namespace bober
{
/// BoberClient class.
class BoberClient
{
public:
/// Get current library version.
static std::string getVersion();
/// Class destructor.
~BoberClient();
/// Initialize BoberClient channel for communication.
bool init(std::string managerIP, std::string boberClientName);
/// Send a message.
bool send(std::string dstName, std::string type, std::string payload, std::string& id);
/// Get an input message from the BoberClient.
bool get(std::string& srcName, std::string& type,
std::string& payload, std::string& id, int timeoutMs = 0);
/// Get connection status.
bool isConnected();
/// Set print flag for debug info.
void setLogMode(cr::utils::PrintFlag printFlag);
/// Close UDP socket.
void close();
};
}
}
getVersion method
The getVersion() method returns string of current class version. Method declaration:
static std::string getVersion();
Method can be used without BoberClient class instance:
std::cout << "BoberClient v: " << cr::bober::BoberClient::getVersion() << std::endl;
Console output:
BoberClient v: 1.0.0
init method
The init(…) initializes BoberClient channel for communication.
bool init(std::string managerIP, std::string boberClientName);
Parameter | Value |
---|---|
managerIP | String argument containing IP number of BoberManager. |
boberClientName | Current service’s name, that is being initialized. |
Returns: TRUE if init with success, or FALSE if not.
send method
The send(…) method sends a message to a specified destination service. The message includes a type, payload, and a unique ID. If no ID is provided, the method generates a new one. Method declaration:
bool send(std::string dstName, std::string type, std::string payload, std::string& id);
Parameter | Value |
---|---|
dstName | The name of the destination service to which the message will be sent. |
type | The type of the message (e.g., Command, Request, Notify, etc.). |
payload | The content or payload of the message. |
id | The unique ID of the message. If an empty string is provided, a new ID is generated. |
Returns: TRUE if the message was sent with success, or FALSE if not.
get method
The get() method retrieves the next available message from the input queue. If no message is available, it waits for a specified timeout or indefinitely based on the provided timeout value. Method declaration:
bool get(std::string& srcName, std::string& type, std::string& payload,
std::string& id, int timeoutMs = 0);
Parameter | Value |
---|---|
srcName | The source service name of the retrieved message. |
type | The type of the retrieved message (e.g., Command, Request, etc.). |
payload | The payload/content of the retrieved message. |
id | The unique ID of the retrieved message. |
Returns: TRUE if the message was retrieved with success, or FALSE if not.
isConnected method
The isConnected(…) method returns client connection status. Method declaration:
bool isConnected();
Returns: TRUE if channel is connected to BoberManager or FALSE if not.
close method
The close() method closes connection. Method declaration:
void close();
setLogMode method
The setLogMode(…) method sets chosen flag how to log debug info.
void setLogMode(cr::utils::PrintFlag printFlag);
Parameter | Value |
---|---|
printFlag | Print flag: disable, console, file or console and file. |
Build and connect to your project
Typical commands to build BoberClient library (on Linux OS):
cd BoberClient
cmake -B build
cmake --build build
If you want connect BoberClient library to your CMake project as source code you can make the following. For example, if your repository has structure:
CMakeLists.txt
src
CMakeList.txt
yourLib.h
yourLib.cpp
Create 3rdparty folder in your repository and copy BoberClient repository folder there. New structure of your repository:
CMakeLists.txt
src
CMakeList.txt
yourLib.h
yourLib.cpp
3rdparty
BoberClient
Create CMakeLists.txt file in 3rdparty folder. CMakeLists.txt should contain:
cmake_minimum_required(VERSION 3.13)
################################################################################
## 3RD-PARTY
## dependencies for the project
################################################################################
project(3rdparty LANGUAGES CXX)
################################################################################
## SETTINGS
## basic 3rd-party settings before use
################################################################################
# To inherit the top-level architecture when the project is used as a submodule.
SET(PARENT ${PARENT}_YOUR_PROJECT_3RDPARTY)
# Disable self-overwriting of parameters inside included subdirectories.
SET(${PARENT}_SUBMODULE_CACHE_OVERWRITE OFF CACHE BOOL "" FORCE)
################################################################################
## CONFIGURATION
## 3rd-party submodules configuration
################################################################################
SET(${PARENT}_SUBMODULE_BOBER_CLIENT ON CACHE BOOL "" FORCE)
if (${PARENT}_SUBMODULE_BOBER_CLIENT)
SET(${PARENT}_BOBER_CLIENT ON CACHE BOOL "" FORCE)
SET(${PARENT}_BOBER_CLIENT_TEST OFF CACHE BOOL "" FORCE)
SET(${PARENT}_BOBER_CLIENT_BENCHMARK OFF CACHE BOOL "" FORCE)
endif()
################################################################################
## INCLUDING SUBDIRECTORIES
## Adding subdirectories according to the 3rd-party configuration
################################################################################
if (${PARENT}_SUBMODULE_BOBER_CLIENT)
add_subdirectory(BoberClient)
endif()
File 3rdparty/CMakeLists.txt adds folder BoberClient to your project and excludes examples from compiling (by default examples excluded from compiling if BoberClient included as sub-repository). Your repository new structure will be:
CMakeLists.txt
src
CMakeList.txt
yourLib.h
yourLib.cpp
3rdparty
CMakeLists.txt
BoberClient
Next you need include folder 3rdparty in main CMakeLists.txt file of your repository. Add string at the end of your main CMakeLists.txt:
add_subdirectory(3rdparty)
Next you have to include BoberClient library in your src/CMakeLists.txt file:
target_link_libraries(${PROJECT_NAME} BoberClient)
Done!
Example application
The BoberClient project includes two executable applications that can be built. The first is a benchmark application, designed to measure the routing time between two clients. The second is a test application, which serves as an example implementation. In the test application, users can specify their service name, destination, and message, and observe the response along with the measured response time. The code for the example test application is provided below:
#include <iostream>
#include <chrono>
#include <thread>
#include "BoberClient.h"
int main(void)
{
std::cout << "BoberClient test v" << cr::bober::BoberClient::getVersion() << std::endl;
std::cout << std::endl;
cr::bober::BoberClient boberClient;
int timeout = 1000;
// Get system IP.
std::string systemIP{ "127.0.0.1" };
std::cout << "Set system IP (default 127.0.0.1): ";
std::cin >> systemIP;
// Get name of current service.
std::string myName = "BoberClient";
std::cout << "Set name of your service (default BoberClient): ";
std::cin >> myName;
// Get command destination.
std::string destinationName = "Dst";
std::cout << "Set destination name: ";
std::cin >> destinationName;
// Initialize connection.
if (!boberClient.init(systemIP, myName))
{
std::cout << "Can't initialize client" << std::endl;
return -1;
}
std::string srcName{ "" };
std::string type{ "" };
std::string payload{ "" };
std::string receivedID{ "" };
std::chrono::time_point<std::chrono::steady_clock> start;
int responseTime = 0;
int sentID = 0;
while (true)
{
sentID++;
std::cout << "Your message type (Command or Request): ";
std::cin >> type;
std::cout << "Your message payload: ";
std::cin >> payload;
// Start counter.
start = std::chrono::steady_clock::now();
// Send data.
if (!boberClient.send(destinationName, type, payload, std::to_string(sentID)))
{
std::cout << "Can't send data" << std::endl;
}
if (!boberClient.get(srcName, type, payload, receivedID, timeout))
{
std::cout << "No response in " << timeout << " ms." << std::endl;
continue;
}
responseTime = static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start).count());
// Show response.
std::cout << "[RX " << responseTime << " ms] " << "[" + receivedID + "]/" +
srcName + "/" + type + "/" + payload << std::endl;
}
return 0;
}
The application output will look like:
BoberClient test v1.0.0
Set system IP (default 127.0.0.1): 127.0.0.1
Set name of your service (default BoberClient): BoberClientB
Set destination name: BoberManager
Your message type (Command or Request): Request
Your message payload: Clients
[RX 1 ms] [1]/BoberManager/Response/Clients:BoberClient,BoberClientB
Your message type (Command or Request):