Skip to content

Commit

Permalink
iox-#27 Add Client/Server example
Browse files Browse the repository at this point in the history
  • Loading branch information
elBoberido committed Feb 10, 2022
1 parent 9ebbaf3 commit 526053c
Show file tree
Hide file tree
Showing 7 changed files with 599 additions and 0 deletions.
120 changes: 120 additions & 0 deletions iceoryx_examples/request_response_basic/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Copyright (c) 2022 by Apex.AI Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

# Build request_response_basic example
cmake_minimum_required(VERSION 3.5)
project(example_request_response_basic)

include(GNUInstallDirs)

find_package(iceoryx_posh REQUIRED)
find_package(iceoryx_hoofs REQUIRED)

get_target_property(ICEORYX_CXX_STANDARD iceoryx_posh::iceoryx_posh CXX_STANDARD)
include(IceoryxPlatform)

## C++ typed API client
add_executable(
iox-cpp-request-response-basic-client
client_cxx_api.cpp
)
target_link_libraries(
iox-cpp-request-response-basic-client
PRIVATE
iceoryx_hoofs::iceoryx_hoofs
iceoryx_posh::iceoryx_posh
)
target_compile_options(
iox-cpp-request-response-basic-client
PRIVATE
${ICEORYX_WARNINGS}
${ICEORYX_SANITIZER_FLAGS}
)

## C++ typed API client with events
add_executable(
iox-cpp-request-response-event-client
client_cxx_api_event.cpp
)
target_link_libraries(
iox-cpp-request-response-event-client
PRIVATE
iceoryx_hoofs::iceoryx_hoofs
iceoryx_posh::iceoryx_posh
)
target_compile_options(
iox-cpp-request-response-event-client
PRIVATE
${ICEORYX_WARNINGS}
${ICEORYX_SANITIZER_FLAGS}
)

## C++ typed API server
add_executable(
iox-cpp-request-response-basic-server
server_cxx_api.cpp
)
target_link_libraries(
iox-cpp-request-response-basic-server
PRIVATE
iceoryx_hoofs::iceoryx_hoofs
iceoryx_posh::iceoryx_posh
)
target_compile_options(
iox-cpp-request-response-basic-server
PRIVATE
${ICEORYX_WARNINGS}
${ICEORYX_SANITIZER_FLAGS}
)

## C++ typed API server with events
add_executable(
iox-cpp-request-response-event-server
server_cxx_api_event.cpp
)
target_link_libraries(
iox-cpp-request-response-event-server
PRIVATE
iceoryx_hoofs::iceoryx_hoofs
iceoryx_posh::iceoryx_posh
)
target_compile_options(
iox-cpp-request-response-event-server
PRIVATE
${ICEORYX_WARNINGS}
${ICEORYX_SANITIZER_FLAGS}
)

## additional properties
set_target_properties(
iox-cpp-request-response-basic-client
iox-cpp-request-response-basic-server
iox-cpp-request-response-event-client
iox-cpp-request-response-event-server
PROPERTIES
CXX_STANDARD_REQUIRED ON
CXX_STANDARD ${ICEORYX_CXX_STANDARD}
POSITION_INDEPENDENT_CODE ON
)

install(
TARGETS
iox-cpp-request-response-basic-client
iox-cpp-request-response-basic-server
iox-cpp-request-response-event-client
iox-cpp-request-response-event-server
RUNTIME DESTINATION bin
)
108 changes: 108 additions & 0 deletions iceoryx_examples/request_response_basic/client_cxx_api.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright (c) 2022 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

//! [iceoryx includes]
#include "request_and_response_types.hpp"

#include "iceoryx_hoofs/posix_wrapper/signal_handler.hpp"
#include "iceoryx_posh/popo/client.hpp"
#include "iceoryx_posh/runtime/posh_runtime.hpp"
//! [iceoryx includes]

#include <atomic>
#include <iostream>

//! [signal handling]
std::atomic<bool> keepRunning{true};

static void sigHandler(int sig IOX_MAYBE_UNUSED)
{
// caught SIGINT or SIGTERM, now exit gracefully
keepRunning = false;
}
//! [signal handling]

int main()
{
//! [register sigHandler]
auto signalIntGuard = iox::posix::registerSignalHandler(iox::posix::Signal::INT, sigHandler);
auto signalTermGuard = iox::posix::registerSignalHandler(iox::posix::Signal::TERM, sigHandler);
//! [register sigHandler]

//! [initialize runtime]
constexpr char APP_NAME[] = "iox-cpp-request-response-client";
iox::runtime::PoshRuntime::initRuntime(APP_NAME);
//! [initialize runtime]

//! [create client]
iox::popo::Client<AddRequest, AddResponse> client({"Example", "Request-Response", "Add"});
//! [create client]

//! [send requests in a loop]
uint64_t fibonacciLast = 0;
uint64_t fibonacciCurrent = 1;
int64_t requestSequenceId = 0;
int64_t expectedResponseSequenceId = requestSequenceId;
while (keepRunning)
{
//! [send request]
client.allocateRequest()
.and_then([&](auto& requestHeader) {
requestHeader->setSequenceId(requestSequenceId);
expectedResponseSequenceId = requestSequenceId;
requestSequenceId += 1;
auto request = static_cast<AddRequest*>(requestHeader->getUserPayload());
request->augend = fibonacciLast;
request->addend = fibonacciCurrent;
std::cout << "Send Request: " << fibonacciLast << " + " << fibonacciCurrent << std::endl;
client.sendRequest(requestHeader);
})
.or_else([](auto& error) {
std::cout << "Could not allocate Request! Return value = " << static_cast<uint64_t>(error) << std::endl;
});
//! [send request]

// the server polls with an interval of 100ms
constexpr std::chrono::milliseconds DELAY_TIME{150U};
std::this_thread::sleep_for(DELAY_TIME);

//! [take response]
while (client.getResponse().and_then([&](auto& responseHeader) {
if (responseHeader->getSequenceId() == expectedResponseSequenceId)
{
auto response = static_cast<const AddResponse*>(responseHeader->getUserPayload());
fibonacciLast = fibonacciCurrent;
fibonacciCurrent = response->sum;
client.releaseResponse(responseHeader);
std::cout << "Got Response : " << fibonacciCurrent << std::endl;
}
else
{
std::cout << "Got Response with outdated sequence ID! Expected = " << expectedResponseSequenceId
<< "; Actual = " << responseHeader->getSequenceId() << "! -> skip" << std::endl;
}
}))
{
};
//! [take response]

constexpr std::chrono::milliseconds SLEEP_TIME{950U};
std::this_thread::sleep_for(SLEEP_TIME);
}
//! [send requests in a loop]

return EXIT_SUCCESS;
}
140 changes: 140 additions & 0 deletions iceoryx_examples/request_response_basic/client_cxx_api_event.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright (c) 2022 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

//! [iceoryx includes]
#include "request_and_response_types.hpp"

#include "iceoryx_hoofs/internal/concurrent/smart_lock.hpp"
#include "iceoryx_hoofs/posix_wrapper/signal_handler.hpp"
#include "iceoryx_posh/popo/client.hpp"
#include "iceoryx_posh/popo/listener.hpp"
#include "iceoryx_posh/popo/notification_callback.hpp"
#include "iceoryx_posh/runtime/posh_runtime.hpp"
//! [iceoryx includes]

#include <atomic>
#include <iostream>

//! [signal handling]
std::atomic<bool> keepRunning{true};

iox::posix::Semaphore shutdownSemaphore =
iox::posix::Semaphore::create(iox::posix::CreateUnnamedSingleProcessSemaphore, 0U).value();

static void sigHandler(int sig IOX_MAYBE_UNUSED)
{
shutdownSemaphore.post().or_else([](auto) {
std::cerr << "unable to call post on shutdownSemaphore - semaphore corrupt?" << std::endl;
std::exit(EXIT_FAILURE);
});
// caught SIGINT or SIGTERM, now exit gracefully
keepRunning = false;
}
//! [signal handling]

struct ContextData
{
uint64_t fibonacciLast = 0;
uint64_t fibonacciCurrent = 1;
int64_t requestSequenceId = 0;
int64_t expectedResponseSequenceId = requestSequenceId;
};

void onResponseReceived(iox::popo::Client<AddRequest, AddResponse>* client,
iox::concurrent::smart_lock<ContextData>* ctx)
{
auto guardedCtx = ctx->getScopeGuard();
//! [take response]
while (client->getResponse().and_then([&](auto& responseHeader) {
if (responseHeader->getSequenceId() == guardedCtx->expectedResponseSequenceId)
{
auto response = static_cast<const AddResponse*>(responseHeader->getUserPayload());
guardedCtx->fibonacciLast = guardedCtx->fibonacciCurrent;
guardedCtx->fibonacciCurrent = response->sum;
client->releaseResponse(responseHeader);
std::cout << "Got Response : " << guardedCtx->fibonacciCurrent << std::endl;
}
else
{
std::cout << "Got Response with outdated sequence ID! Expected = " << guardedCtx->expectedResponseSequenceId
<< "; Actual = " << responseHeader->getSequenceId() << "! -> skip" << std::endl;
}
}))
{
}
//! [take response]
}

int main()
{
//! [register sigHandler]
auto signalIntGuard = iox::posix::registerSignalHandler(iox::posix::Signal::INT, sigHandler);
auto signalTermGuard = iox::posix::registerSignalHandler(iox::posix::Signal::TERM, sigHandler);
//! [register sigHandler]

//! [initialize runtime]
constexpr char APP_NAME[] = "iox-cpp-request-response-client-event";
iox::runtime::PoshRuntime::initRuntime(APP_NAME);
//! [initialize runtime]

iox::popo::Listener listener;

//! [create client]
iox::popo::Client<AddRequest, AddResponse> client({"Example", "Request-Response", "Add"});
//! [create client]

iox::concurrent::smart_lock<ContextData> ctx;

listener
.attachEvent(client,
iox::popo::ClientEvent::RESPONSE_RECEIVED,
iox::popo::createNotificationCallback(onResponseReceived, ctx))
.or_else([](auto) {
std::cerr << "unable to attach server" << std::endl;
std::exit(EXIT_FAILURE);
});

//! [send requests in a loop]
while (keepRunning)
{
//! [send request]
client.allocateRequest()
.and_then([&](auto& requestHeader) {
auto guardedCtx = ctx.getScopeGuard();
requestHeader->setSequenceId(guardedCtx->requestSequenceId);
guardedCtx->expectedResponseSequenceId = guardedCtx->requestSequenceId;
guardedCtx->requestSequenceId += 1;
auto request = static_cast<AddRequest*>(requestHeader->getUserPayload());
request->augend = guardedCtx->fibonacciLast;
request->addend = guardedCtx->fibonacciCurrent;
std::cout << "Send Request: " << guardedCtx->fibonacciLast << " + " << guardedCtx->fibonacciCurrent
<< std::endl;
client.sendRequest(requestHeader);
})
.or_else([](auto& error) {
std::cout << "Could not allocate Request! Return value = " << static_cast<uint64_t>(error) << std::endl;
});
//! [send request]

constexpr std::chrono::milliseconds SLEEP_TIME{1000U};
std::this_thread::sleep_for(SLEEP_TIME);
}
//! [send requests in a loop]

listener.detachEvent(client, iox::popo::ClientEvent::RESPONSE_RECEIVED);

return EXIT_SUCCESS;
}
Loading

0 comments on commit 526053c

Please sign in to comment.