TCP and preparation

This commit is contained in:
ackimixs
2024-03-27 18:05:32 +01:00
parent fac4ff7aee
commit aef800f2f2
17 changed files with 760 additions and 44 deletions

View File

@@ -7,32 +7,57 @@ set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(HEADERS
MainWindow.h
homeButton.h
Homologation.h
InGame.h
TeamChooser.h
TestMode.h
TestModeBtn.h
preparation/TiretteState.h
preparation/Lidar.h
PreparationMatch.h
preparation/OneItemPreparation.h
)
set(SOURCES
main.cpp
MainWindow.cpp
homeButton.cpp
Homologation.cpp
InGame.cpp
TeamChooser.cpp
TestMode.cpp
TestModeBtn.cpp
PreparationMatch.cpp
preparation/Lidar.cpp
preparation/OneItemPreparation.cpp
preparation/TiretteState.cpp
)
set(TCP
tcp/TCPServer.hpp
tcp/TCPServer.cpp
tcp/utils.hpp
tcp/QTTCPSocketServer.cpp
tcp/QTTCPSocketServer.h
)
find_package(Qt6 COMPONENTS
Core
Gui
Widgets
Network
REQUIRED)
add_executable(ihm_robot main.cpp resource.qrc
MainWindow.cpp
MainWindow.h
homeButton.cpp
homeButton.h
Homologation.cpp
Homologation.h
InGame.cpp
InGame.h
TeamChooser.cpp
TeamChooser.h
TestMode.cpp
TestMode.h
TestModeBtn.cpp
TestModeBtn.h
)
add_executable(ihm_robot resource.qrc ${HEADERS} ${SOURCES} ${TCP})
target_link_libraries(ihm_robot
Qt::Core
Qt::Gui
Qt::Widgets
Qt::Network
)

View File

@@ -1,12 +1,14 @@
#pragma once
#include <QMainWindow>
#include <QWidget>
#include <QStackedWidget>
#include <QIcon>
#include <QPixmap>
#include "homeButton.h"
#include "Homologation.h"
#include "InGame.h"
#include "PreparationMatch.h"
#include "TeamChooser.h"
#include "TestMode.h"
@@ -58,9 +60,12 @@ public:
connect(this->homologation, &Homologation::replierClicked, this, &MainWindow::replierRobot);
this->teamChooser = new TeamChooser(centralWidget);
connect(this->teamChooser, &TeamChooser::blueTeamClicked, this, &MainWindow::onInGamePressed);
connect(this->teamChooser, &TeamChooser::spawnPointChoose, this, &MainWindow::onSpawnPointChoose);
connect(this->teamChooser, &TeamChooser::yellowTeamClicked, this, &MainWindow::onInGamePressed);
this->preparationMatch = new PreparationMatch(centralWidget);
connect(this->preparationMatch, &PreparationMatch::startGame, this, &MainWindow::onStartGame);
// connect(this->preparationMatch, &PreparationMatch::askTCPServer, this, &MainWindow::broadcastTCPMessage);
connect(this->preparationMatch, &PreparationMatch::askTCPServer, this, &MainWindow::broadcastTCPMessage);
this->testMode = new TestMode(centralWidget);
connect(this->testMode, &TestMode::goPressed, this, &MainWindow::moveRobot);
@@ -71,6 +76,7 @@ public:
this->stackedWidget->addWidget(this->home);
this->stackedWidget->addWidget(this->homologation);
this->stackedWidget->addWidget(this->teamChooser);
this->stackedWidget->addWidget(this->preparationMatch);
this->stackedWidget->addWidget(this->testMode);
this->stackedWidget->addWidget(this->inGame);
@@ -86,11 +92,15 @@ public:
QPalette palette;
palette.setBrush(this->backgroundRole(), QBrush(QPixmap(":/img/table.jpg", "JPG").scaled(this->size(), Qt::IgnoreAspectRatio)));
this->setPalette(palette);
this->homeBtn->hide();
this->quit->hide();
} else
{
QPalette palette;
palette.setBrush(this->backgroundRole(), QBrush(Qt::white));
this->setPalette(palette);
this->homeBtn->show();
this->quit->show();
}
this->stackedWidget->setCurrentIndex(index);
}
@@ -112,13 +122,18 @@ protected slots:
}
void onTestModePressed()
{
this->setWidgetNb(4);
}
void onSpawnPointChoose(int nb)
{
this->setWidgetNb(3);
}
void onInGamePressed()
void onStartGame()
{
this->setWidgetNb(4);
this->setWidgetNb(5);
}
void onDeplierRobot()
@@ -131,10 +146,24 @@ protected slots:
emit replierRobot();
}
public slots:
void onTCPMesssageReceived(const std::string& message)
{
QString qMessage = QString::fromStdString(message);
auto list = qMessage.split(";");
if (list[2].startsWith("pong"))
{
preparationMatch->responseFromPing(qMessage);
}
}
signals:
void deplierRobot();
void replierRobot();
void moveRobot(int x, int y, int theta);
void broadcastTCPMessage(const std::string& message);
private:
QVBoxLayout* mainLayout;
@@ -147,6 +176,7 @@ private:
homeButton* home;
Homologation* homologation;
TeamChooser* teamChooser;
PreparationMatch* preparationMatch;
TestMode* testMode;
InGame* inGame;
};

5
PreparationMatch.cpp Normal file
View File

@@ -0,0 +1,5 @@
//
// Created by acki on 3/27/24.
//
#include "PreparationMatch.h"

115
PreparationMatch.h Normal file
View File

@@ -0,0 +1,115 @@
#pragma once
#include <QWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include "preparation/Lidar.h"
#include "preparation/OneItemPreparation.h"
#include "preparation/TiretteState.h"
class PreparationMatch : public QWidget {
Q_OBJECT
public:
PreparationMatch(QWidget* parent = nullptr) : QWidget(parent)
{
this->mainLayout = new QVBoxLayout(this);
this->gridLayout = new QHBoxLayout();
this->startButton = new QPushButton("Play", this);
this->leftLayout = new QVBoxLayout();
this->lidar = new Lidar(this);
this->leftLayout->addWidget(lidar);
this->tiretteState = new TiretteState(this);
this->leftLayout->addWidget(tiretteState);
this->rightLayout = new QVBoxLayout();
this->ledVerte = new OneItemPreparation("Led verte", "Check", this);
connect(this->ledVerte, &OneItemPreparation::buttonClicked, this, [=]() {
this->ledVerte->toggleChecked();
});
this->arduino = new OneItemPreparation("Arduino", "Ping", this);
connect(this->arduino, &OneItemPreparation::buttonClicked, this, [=]() {
// emit askTCPServer("start;tirette;ping;0");
this->arduino->toggleChecked();
});
this->aruco = new OneItemPreparation("Aruco", "Ping", this);
connect(this->aruco, &OneItemPreparation::buttonClicked, this, [=]() {
emit askTCPServer("strat;aruco;ping;0");
});
this->lidarPing = new OneItemPreparation("Lidar", "Ping", this);
connect(this->lidarPing, &OneItemPreparation::buttonClicked, this, [=]() {
emit askTCPServer("strat;lidar;ping;0");
});
this->tirette = new OneItemPreparation("Tirette", "Ping", this);
connect(this->tirette, &OneItemPreparation::buttonClicked, this, [=]() {
emit askTCPServer("strat;tirette;ping;0");
});
this->rightLayout->addWidget(ledVerte);
this->rightLayout->addWidget(arduino);
this->rightLayout->addWidget(aruco);
this->rightLayout->addWidget(lidarPing);
this->rightLayout->addWidget(tirette);
this->gridLayout->addLayout(leftLayout);
this->gridLayout->addLayout(rightLayout);
this->mainLayout->addLayout(gridLayout);
this->mainLayout->addWidget(startButton);
connect(this->startButton, &QPushButton::pressed, this, &PreparationMatch::onStartButtonClicked);
}
void responseFromPing(const QString& message)
{
auto list = message.split(";");
if (list[0] == "tirette") {
this->tirette->setChecked(true);
} else if (list[0] == "lidar") {
this->lidarPing->setChecked(true);
} else if (list[0] == "aruco") {
this->aruco->setChecked(true);
}
// TODO check how we ping the arduino
/*else if (list[0] == "arduino") {
this->arduino->setChecked(true);
}*/
}
signals:
void startGame();
void askTCPServer(const std::string& message);
public slots:
void onStartButtonClicked()
{
emit startGame();
}
private:
QVBoxLayout* mainLayout;
QHBoxLayout* gridLayout;
QVBoxLayout* leftLayout;
QVBoxLayout* rightLayout;
Lidar* lidar;
OneItemPreparation* ledVerte;
OneItemPreparation* arduino;
OneItemPreparation* aruco;
OneItemPreparation* lidarPing;
OneItemPreparation* tirette;
TiretteState* tiretteState;
QPushButton* startButton;
};

View File

@@ -8,36 +8,90 @@ class TeamChooser : public QWidget {
public:
TeamChooser(QWidget* parent = nullptr) : QWidget(parent)
{
this->mainLayout = new QHBoxLayout(this);
this->blueTeam = new QPushButton("Equipe Bleue", this);
this->blueTeam->setStyleSheet("background-color: #4D83A1; border-radius: 40px; margin-top: 20px; color: black;");
this->yellowTeam = new QPushButton("Equipe Jaune", this);
this->yellowTeam->setStyleSheet("background-color: #FFBF00; border-radius: 40px; margin-top: 20px; color: black;");
// set a border
// this->setStyleSheet("border: 10px solid black;");
this->mainLayout->addWidget(this->blueTeam);
this->mainLayout->addWidget(this->yellowTeam);
this->mainLayout = new QVBoxLayout(this);
connect(this->blueTeam, &QPushButton::pressed, this, &TeamChooser::onBlueTeamClicked);
connect(this->yellowTeam, &QPushButton::pressed, this, &TeamChooser::onYellowTeamClicked);
this->topLayout = new QHBoxLayout();
this->middleLayout = new QHBoxLayout();
this->bottomLayout = new QHBoxLayout();
this->spawnPoint1 = new QPushButton("1", this);
this->spawnPoint1->setFixedSize(50, 50);
this->spawnPoint1->setStyleSheet("border: 1px solid black; color: white; background-color: rgba(0, 0, 255, 200);");
this->spawnPoint2 = new QPushButton("2", this);
this->spawnPoint2->setFixedSize(50, 50);
this->spawnPoint2->setStyleSheet("border: 1px solid black; color: black; background-color: rgba(255, 255, 0, 200);");
this->spawnPoint3 = new QPushButton("3", this);
this->spawnPoint3->setFixedSize(50, 50);
this->spawnPoint3->setStyleSheet("border: 1px solid black; color: white; background-color: rgba(0, 0, 255, 200);");
this->spawnPoint4 = new QPushButton("4", this);
this->spawnPoint4->setFixedSize(50, 50);
this->spawnPoint4->setStyleSheet("border: 1px solid black; color: black; background-color: rgba(255, 255, 0, 200);");
this->spawnPoint5 = new QPushButton("5", this);
this->spawnPoint5->setFixedSize(50, 50);
this->spawnPoint5->setStyleSheet("border: 1px solid black; color: white; background-color: rgba(0, 0, 255, 200);");
this->spawnPoint6 = new QPushButton("6", this);
this->spawnPoint6->setFixedSize(50, 50);
this->spawnPoint6->setStyleSheet("border: 1px solid black; color: black; background-color: rgba(255, 255, 0, 200);");
this->mainLayout->addLayout(topLayout);
this->mainLayout->addLayout(middleLayout);
this->mainLayout->addLayout(bottomLayout);
this->topLayout->addWidget(spawnPoint1, 0, Qt::AlignTop | Qt::AlignLeft);
this->middleLayout->addWidget(spawnPoint2, 0, Qt::AlignCenter | Qt::AlignLeft);
this->bottomLayout->addWidget(spawnPoint3, 0, Qt::AlignBottom | Qt::AlignLeft);
this->topLayout->addWidget(spawnPoint4, 0, Qt::AlignTop | Qt::AlignRight);
this->middleLayout->addWidget(spawnPoint5, 0, Qt::AlignCenter | Qt::AlignRight);
this->bottomLayout->addWidget(spawnPoint6, 0, Qt::AlignBottom | Qt::AlignRight);
connect(this->spawnPoint1, &QPushButton::pressed, this, [=]() {
spawnPointClicked(1);
});
connect(this->spawnPoint2, &QPushButton::pressed, this, [=]() {
spawnPointClicked(2);
});
connect(this->spawnPoint3, &QPushButton::pressed, this, [=]() {
spawnPointClicked(3);
});
connect(this->spawnPoint4, &QPushButton::pressed, this, [=]() {
spawnPointClicked(4);
});
connect(this->spawnPoint5, &QPushButton::pressed, this, [=]() {
spawnPointClicked(5);
});
connect(this->spawnPoint6, &QPushButton::pressed, this, [=]() {
spawnPointClicked(6);
});
}
signals:
void blueTeamClicked();
void yellowTeamClicked();
void spawnPointChoose(int nb);
private slots:
void onBlueTeamClicked()
void spawnPointClicked(int nb)
{
emit blueTeamClicked();
}
void onYellowTeamClicked()
{
emit yellowTeamClicked();
emit spawnPointChoose(nb);
}
private:
QHBoxLayout* mainLayout;
QPushButton* blueTeam;
QPushButton* yellowTeam;
QVBoxLayout* mainLayout;
QHBoxLayout* topLayout;
QHBoxLayout* middleLayout;
QHBoxLayout* bottomLayout;
QPushButton* spawnPoint1;
QPushButton* spawnPoint2;
QPushButton* spawnPoint3;
QPushButton* spawnPoint4;
QPushButton* spawnPoint5;
QPushButton* spawnPoint6;
};

View File

@@ -1,7 +1,10 @@
#include <iostream>
#include <QApplication>
#include <QObject>
#include <QThread>
#include "MainWindow.h"
#include "tcp/TCPServer.hpp"
int main(int argc, char* argv[]) {
QApplication a(argc, argv);
@@ -23,9 +26,50 @@ int main(int argc, char* argv[]) {
qInfo() << "move" << x << y << theta;
});
//main->show();
main->show();
// main->showFullScreen();
main->showFullScreen();
auto* server = new TCPServer(8082);
server->start();
QObject::connect(server, &TCPServer::messageReceived, main, &MainWindow::onTCPMesssageReceived);
QObject::connect(main, &MainWindow::broadcastTCPMessage, [server](const std::string& message)
{
server->broadcastMessage(message.c_str());
});
// Create a new thread for the server
QThread serverThread;
server->moveToThread(&serverThread);
serverThread.start();
// Create a lambda function to run the while loop
auto runServerLoop = [&]() {
while (true) {
std::string message;
std::cout << "Enter message ('quit' to exit): ";
std::getline(std::cin, message);
if (message == "quit") {
// Stop the server and exit the loop
server->stop();
break;
}
// Broadcast the message from the server
server->broadcastMessage(message.c_str());
}
};
// Move the lambda function to the new thread
QObject::connect(&serverThread, &QThread::started, runServerLoop);
// Connect aboutToQuit signal to stop the thread and wait for it to finish
QObject::connect(&a, &QCoreApplication::aboutToQuit, [&]() {
server->stop(); // Stop the server
serverThread.quit(); // Quit the thread event loop
serverThread.wait(); // Wait for the thread to finish
});
return QApplication::exec();
}

5
preparation/Lidar.cpp Normal file
View File

@@ -0,0 +1,5 @@
//
// Created by acki on 3/27/24.
//
#include "Lidar.h"

48
preparation/Lidar.h Normal file
View File

@@ -0,0 +1,48 @@
#pragma once
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
class Lidar : public QWidget {
Q_OBJECT
public:
Lidar(QWidget* parent = nullptr) : QWidget(parent)
{
this->mainLayout = new QVBoxLayout(this);
this->mainLayout->setAlignment(Qt::AlignTop);
this->title = new QLabel("Lidar", this);
this->title->setStyleSheet("font-size: 24px; color: black;");
this->position = new QHBoxLayout();
this->postionTitle = new QLabel("x: 0, y : 0, r: 0", this);
this->positionButton = new QPushButton("Get pos", this);
this->position->addWidget(postionTitle);
this->position->addWidget(positionButton);
this->health = new QHBoxLayout();
this->healthTitle = new QLabel("Health : OK", this);
this->healthButton = new QPushButton("Get health", this);
this->health->addWidget(healthTitle);
this->health->addWidget(healthButton);
this->mainLayout->addWidget(title, 0, Qt::AlignCenter);
this->mainLayout->addLayout(position);
this->mainLayout->addLayout(health);
}
private:
QVBoxLayout* mainLayout;
QLabel* title;
QHBoxLayout* position;
QHBoxLayout* health;
QLabel* postionTitle;
QPushButton* positionButton;
QLabel* healthTitle;
QPushButton* healthButton;
};

View File

@@ -0,0 +1,5 @@
//
// Created by acki on 3/27/24.
//
#include "OneItemPreparation.h"

View File

@@ -0,0 +1,54 @@
#pragma once
#include <QHBoxLayout>
#include <QLabel>
#include <QWidget>
#include <QCheckBox>
#include <QPushButton>
class OneItemPreparation : public QWidget {
Q_OBJECT
public:
OneItemPreparation(const QString& title, const QString& buttonText, QWidget* parent = nullptr) : QWidget(parent)
{
this->mainLayout = new QHBoxLayout(this);
this->item = new QLabel(title, this);
this->checkBox = new QCheckBox(this);
this->button = new QPushButton(buttonText, this);
this->mainLayout->addWidget(item);
this->mainLayout->addWidget(checkBox);
this->mainLayout->addWidget(button);
this->checkBox->setDisabled(true);
connect(this->button, &QPushButton::pressed, this, &OneItemPreparation::onButtonClicked);
}
void setChecked(const bool checked) const
{
this->checkBox->setChecked(checked);
}
void toggleChecked() const
{
this->checkBox->toggle();
}
signals:
void buttonClicked();
public slots:
void onButtonClicked()
{
emit buttonClicked();
}
private:
QHBoxLayout* mainLayout;
QLabel* item;
QCheckBox* checkBox;
QPushButton* button;
};

View File

@@ -0,0 +1,5 @@
//
// Created by acki on 3/27/24.
//
#include "TiretteState.h"

View File

@@ -0,0 +1,33 @@
#pragma once
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QWidget>
class TiretteState : public QWidget {
Q_OBJECT
public:
TiretteState(QWidget* parent = nullptr) : QWidget(parent)
{
this->mainLayout = new QVBoxLayout(this);
this->title = new QLabel("Tirette", this);
this->title->setStyleSheet("font-size: 24px; color: black;");
this->tiretteStateLayout = new QHBoxLayout();
this->stateLabel = new QLabel("1 : ", this);
this->stateButton = new QPushButton("Get state", this);
this->tiretteStateLayout->addWidget(stateLabel);
this->tiretteStateLayout->addWidget(stateButton);
this->mainLayout->addWidget(this->title, 0, Qt::AlignCenter);
this->mainLayout->addLayout(this->tiretteStateLayout);
}
private:
QVBoxLayout* mainLayout;
QLabel* title;
QHBoxLayout* tiretteStateLayout;
QLabel* stateLabel;
QPushButton* stateButton;
};

9
tcp/CMakeLists.txt Normal file
View File

@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.25)
project(socketServer)
set(CMAKE_CXX_STANDARD 17)
add_executable(socketServer main.cpp
TCPServer.cpp
TCPServer.hpp
utils.hpp)

149
tcp/TCPServer.cpp Normal file
View File

@@ -0,0 +1,149 @@
#include "TCPServer.hpp"
#include "utils.hpp"
ClientHandler::ClientHandler(int clientSocket, TCPServer* server) : clientSocket(clientSocket), server(server) {};
void ClientHandler::handle() {
std::string buffer;
buffer.reserve(4096); // Pre-allocate memory to avoid frequent allocations
while (true) {
char tempBuffer[4096] = {0};
ssize_t valread = recv(clientSocket, tempBuffer, sizeof(tempBuffer), 0);
if (valread > 0) {
buffer.append(tempBuffer, valread);
//std::cout << "Received: " << buffer << std::endl;
if (buffer == "quit") {
std::cout << "Client requested to quit. Closing connection." << std::endl;
break;
}
processMessage(buffer);
buffer.clear();
} else if (valread == 0) {
std::cout << "Client disconnected." << std::endl;
break; // Client disconnected
} else {
std::cerr << "Failed to receive data." << std::endl;
break; // Error in receiving data
}
}
closeConnection();
}
void ClientHandler::processMessage(const std::string& message) {
server->handleMessage(message, clientSocket);
}
void ClientHandler::closeConnection() {
close(clientSocket);
server->clientDisconnected(clientSocket); // Inform the server that the client has disconnected
}
TCPServer::TCPServer(int port, QObject* parent) : QObject(parent)
{
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == -1) {
std::cerr << "Socket creation failed" << std::endl;
exit(EXIT_FAILURE);
}
sockaddr_in address{};
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
if (bind(serverSocket, reinterpret_cast<struct sockaddr*>(&address), sizeof(address)) == -1) {
std::cerr << "Binding failed" << std::endl;
exit(EXIT_FAILURE);
}
if (listen(serverSocket, 5) == -1) {
std::cerr << "Listening failed" << std::endl;
exit(EXIT_FAILURE);
}
std::cout << "Server started on port " << port << std::endl;
}
void TCPServer::acceptConnections()
{
while (!shouldStop) {
sockaddr_in clientAddress{};
int addrlen = sizeof(clientAddress);
int clientSocket =
accept(serverSocket, reinterpret_cast<struct sockaddr*>(&clientAddress), reinterpret_cast<socklen_t*>(&addrlen));
if (clientSocket == -1) {
std::cerr << "Accepting connection failed" << std::endl;
continue;
}
std::cout << "Connection accepted" << std::endl;
// Add the client socket to the list
clientSockets.push_back(clientSocket);
connectedClients++;
// Handle client connection in a separate thread
clientThreads.emplace_back(&ClientHandler::handle, ClientHandler(clientSocket, this));
// Clean up finished threads
clientThreads.erase(std::remove_if(clientThreads.begin(), clientThreads.end(), [](std::thread &t) {
return !t.joinable();
}), clientThreads.end());
}
}
void TCPServer::handleMessage(const std::string& message, int clientSocket)
{
emit messageReceived(message, clientSocket);
}
void TCPServer::broadcastMessage(const char* message, int senderSocket)
{
for (int clientSocket : clientSockets) {
if (clientSocket != senderSocket) { // Exclude the sender's socket
send(clientSocket, message, strlen(message), 0);
}
}
}
void TCPServer::clientDisconnected(const int clientSocket) {
// Remove the disconnected client's socket
clientSockets.erase(std::remove(clientSockets.begin(), clientSockets.end(), clientSocket), clientSockets.end());
// Decrement the count of connected clients
connectedClients--;
}
void TCPServer::stop() {
shouldStop = true;
// Close all client sockets
for (int clientSocket : clientSockets) {
close(clientSocket);
}
// Close the server socket
close(serverSocket);
}
TCPServer::~TCPServer() {
this->stop();
// Join all threads before exiting
for (auto& thread : clientThreads) {
thread.join();
}
}
int TCPServer::nbClients()
{
return connectedClients;
}
void TCPServer::start()
{
std::thread([this]() { acceptConnections(); }).detach();
}

61
tcp/TCPServer.hpp Normal file
View File

@@ -0,0 +1,61 @@
#pragma once
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <cstring>
#include <thread>
#include <vector>
#include <algorithm>
#include <QObject>
class TCPServer; // Forward declaration
class ClientHandler {
private:
int clientSocket;
TCPServer* server; // Reference to the TCPServer instance
public:
explicit ClientHandler(int clientSocket, TCPServer* server);
void handle();
void processMessage(const std::string& message);
void closeConnection();
};
class TCPServer : public QObject {
Q_OBJECT
int serverSocket;
std::vector<std::thread> clientThreads;
std::vector<int> clientSockets; // Store connected client sockets
int connectedClients = 0; // Track the number of connected clients
bool shouldStop = false; // Flag to indicate if the server should stop
public:
explicit TCPServer(int port, QObject* parent = nullptr);
void start();
void acceptConnections();
// Broadcast message to all connected clients
void broadcastMessage(const char* message, int senderSocket = -1); // Modified method signature
void handleMessage(const std::string& message, int clientSocket = -1);
void clientDisconnected(int clientSocket); // New method to handle client disconnection
void stop();
int nbClients();
~TCPServer();
signals:
void messageReceived(const std::string& message, int clientSocket);
};

36
tcp/main.cpp Normal file
View File

@@ -0,0 +1,36 @@
#include <atomic>
#include <csignal>
#include "TCPServer.hpp"
std::atomic<bool> keepRunning(true);
void signalHandler(int signum) {
std::cout << "Interrupt signal (" << signum << ") received.\n";
keepRunning = false;
}
int main() {
signal(SIGTERM, signalHandler);
signal(SIGINT, signalHandler);
TCPServer server(8080);
try {
server.start();
while (keepRunning) {
sleep(1);
server.broadcastMessage("request aruco");
std::cout << "Main thread communicating with server..." << std::endl;
}
server.stop();
} catch (const std::exception& ex) {
std::cerr << "Error: " << ex.what() << std::endl;
return 1;
}
return 0;
}

38
tcp/utils.hpp Normal file
View File

@@ -0,0 +1,38 @@
#pragma once
#include <vector>
#include <string>
inline bool startWith(const std::string& str, const std::string& start)
{
return str.rfind(start, 0) == 0;
}
inline bool endsWith(const std::string& str, const std::string& end)
{
if (str.length() >= end.length())
{
return (0 == str.compare(str.length() - end.length(), end.length(), end));
}
return false;
}
inline bool contains(const std::string& str, const std::string& sub)
{
return str.find(sub) != std::string::npos;
}
inline std::vector<std::string> split(const std::string& str, const std::string& delimiter)
{
std::vector<std::string> tokens;
size_t prev = 0, pos = 0;
do
{
pos = str.find(delimiter, prev);
if (pos == std::string::npos) pos = str.length();
std::string token = str.substr(prev, pos - prev);
if (!token.empty()) tokens.push_back(token);
prev = pos + delimiter.length();
} while (pos < str.length() && prev < str.length());
return tokens;
}