IRSOL
C++ code implementing socket server for interacting with Baumer camera.
main.cpp
Go to the documentation of this file.
1
13
14#include "irsol/irsol.hpp"
15#include "sockpp/tcp_acceptor.h"
16#include "sockpp/tcp_connector.h"
17
18#include <chrono>
19#include <random>
20#include <string>
21#include <thread>
22#include <vector>
23
24const std::string
26{
27#ifndef PROGRAM_NAME
28#define PROGRAM_NAME "client-server-interaction-demo"
29#endif
30 return PROGRAM_NAME;
31}
32
34std::thread
36{
37
38 return std::thread([&app]() -> void {
39 if(!app.start()) {
40 IRSOL_LOG_FATAL("Failed to start server.");
41 }
42 });
43}
44
46void
48 std::string clientName,
50 std::vector<std::string> commands)
51{
52 std::random_device rd;
53 std::mt19937 gen(rd());
54 std::uniform_int_distribution<> waitDist(40, 1000); // ms
55
56 // Connect to the server at localhost (it is running on the same machine, in a different thread)
57 std::error_code ec;
58 std::string host = "127.0.0.1";
59 irsol::types::connector_t conn({host, port}, ec);
60 if(ec) {
61 IRSOL_LOG_WARN("Failed to connect to server at {}:{}: {}", host, port, ec.message());
62 return;
63 }
64 IRSOL_NAMED_LOG_INFO(clientName, "Connected to server");
65
66 for(const auto& command : commands) {
67 auto waitMs = waitDist(gen);
68 std::this_thread::sleep_for(std::chrono::milliseconds(waitMs));
69 IRSOL_NAMED_LOG_INFO(clientName, "Sending command: '{}'", command);
70 conn.write(command.data(), command.size());
71
72 char buf[256];
73 auto result = conn.read(buf, sizeof(buf) - 1);
74 if(result.value() > 0) {
75 buf[result.value()] = '\0';
76 IRSOL_NAMED_LOG_INFO(clientName, "Received reply: {}", buf);
77 } else {
78 IRSOL_NAMED_LOG_WARN(clientName, "No reply or connection closed");
79 break;
80 }
81 }
82 IRSOL_NAMED_LOG_INFO(clientName, "Client done");
83}
84
86std::thread
88 const std::string& clientName,
90 const std::vector<std::string> commands)
91{
92 return std::thread(clientThreadBody, clientName, port, commands);
93}
94
96struct Params
97{
99 uint32_t numClients{1};
100};
101
111Params
112getParams(int argc, char** argv)
113{
114 args::ArgumentParser parser(getProgramName());
115 args::HelpFlag help(parser, "help", "Display this help menu", {'h', "help"});
116
117 args::ValueFlag<uint32_t> numClientsArg(
118 parser, "#clients", "Number of clients to run concurrently", {'c', "clients"});
119
120 try {
121 parser.ParseCLI(argc, argv);
122 } catch(args::Help) {
123 std::cout << parser.Help() << std::endl;
124 std::exit(0);
125 } catch(args::ParseError& e) {
126 std::cerr << "Error parsing command-line arguments:\n" << e.what() << "\n\n" << parser.Help();
127 std::exit(1);
128 }
129
130 Params params{};
131 if(numClientsArg) {
132 params.numClients = args::get(numClientsArg);
133 }
134 return params;
135}
136
137void
138runDemo(uint32_t numClients)
139{
140 irsol::types::port_t port = 12345;
141 irsol::server::App app(port);
142
143 // Start server thread
144 std::thread serverThread = runServerThread(app);
145
146 // Start multiple clients
147 std::vector<std::thread> clientThreads;
148 std::vector<std::string> sampleCommands = {"fr?\n",
149 "it=300\n",
150 "fr=10.0\n",
151 "isl=20\n",
152 "isl?\n",
153 "fr=0.5\n",
154 "it=500\n",
155 "fr?\n",
156 "it=1000\n"};
157 for(size_t i = 0; i < numClients; ++i) {
158 std::string clientName = "Client" + std::to_string(i + 1);
159 // Create a shuffled copy of sampleCommands for each client
160 std::vector<std::string> shuffledCommands = sampleCommands;
161 std::shuffle(
162 shuffledCommands.begin(), shuffledCommands.end(), std::mt19937(std::random_device()()));
163 clientThreads.emplace_back(runClientThread(clientName, port, shuffledCommands));
164 }
165
166 // Wait for all clients to finish
167 for(auto& t : clientThreads) {
168 if(t.joinable())
169 t.join();
170 }
171
172 // Stop server and wait for it to finish
173 app.stop();
174 if(serverThread.joinable())
175 serverThread.join();
176}
177
179int
180main(int argc, char** argv)
181{
182 // Parse command-line parameters
183 Params params = getParams(argc, argv);
184
185 // Construct log file path based on program name
186 std::string logPath = "logs/" + getProgramName() + ".log";
187 irsol::initLogging(logPath.c_str());
188
189 // Enable custom assertion handler
191
192 runDemo(params.numClients);
193 return 0;
194}
Main server application that manages client connections and camera streaming.
Definition app.hpp:46
void stop()
Stops the server.
Definition app.cpp:39
bool start()
Starts the server.
Definition app.cpp:26
const std::string getProgramName()
Returns the program name, typically used for logging. If PROGRAM_NAME is not defined at compile time,...
Definition main.cpp:12
#define PROGRAM_NAME
int main()
Definition main.cpp:90
Params getParams(int argc, char **argv)
Parses command-line arguments using args library.
Definition main.cpp:54
std::thread runClientThread(const std::string &clientName, irsol::types::port_t port, const std::vector< std::string > commands)
TCP client that connects to the server and sends commands at random intervals.
Definition main.cpp:87
void runDemo(uint32_t numClients)
Definition main.cpp:138
void clientThreadBody(std::string clientName, irsol::types::port_t port, std::vector< std::string > commands)
The function executed by each client thread.
Definition main.cpp:47
std::thread runServerThread(irsol::server::App &app)
Demonstrates handler creation, registration, and dispatch.
Definition main.cpp:35
void initAssertHandler()
Initializes the assertion handler system.
Definition assert.cpp:14
#define IRSOL_NAMED_LOG_INFO(name,...)
Logs an info-level message using a named logger.
Definition logging.hpp:176
#define IRSOL_LOG_WARN(...)
Logs a warning-level message using the default logger.
Definition logging.hpp:93
#define IRSOL_NAMED_LOG_WARN(name,...)
Logs a warning-level message using a named logger.
Definition logging.hpp:178
void initLogging(const char *fileSinkFilename="logs/irsol.log", std::optional< spdlog::level::level_enum > minLogLevel=std::nullopt)
Initializes the irsol logging system.
Definition logging.cpp:108
uint16_t port_t
Represents a network port number. Typically used to specify TCP or UDP ports.
Definition types.hpp:48
sockpp::tcp_connector connector_t
Alias for the TCP client connector type.
Definition types.hpp:71
Command-line parameters for the program.
uint32_t numClients
Number of clients to run concurrently (default: 1)
Definition main.cpp:99
auto result