#include "TCPServer.h" 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) { 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(&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(&clientAddress), reinterpret_cast(&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) { std::cout << "Received: " << message << std::endl; } 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(); }