Implementiere sanften Shutdown und verbessere Server-Stopp-Logik
- Füge Signalhandler in `main.cpp` hinzu, um einen sanften Shutdown bei SIGINT und SIGTERM zu ermöglichen. - Aktualisiere die `Server`- und `SSLServer`-Klassen, um die Stopp-Logik zu verbessern und Threads ordnungsgemäß zu beenden. - Optimiere die Timeout-Werte in der `run`-Methode für eine schnellere Reaktion auf Shutdown-Signale. - Ergänze Logging für den Server-Stopp-Prozess zur besseren Nachverfolgbarkeit.
This commit is contained in:
@@ -13,6 +13,8 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <sstream>
|
||||
#include <regex>
|
||||
#include <errno.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace Yc {
|
||||
namespace Lib {
|
||||
@@ -63,13 +65,33 @@ namespace Yc {
|
||||
}
|
||||
}
|
||||
|
||||
Server::~Server() {
|
||||
stop();
|
||||
if (_socket >= 0) {
|
||||
close(_socket);
|
||||
_socket = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void Server::stop() {
|
||||
std::cout << "[YourChat] Stopping regular server..." << std::endl;
|
||||
_stop = true;
|
||||
|
||||
// Stop all rooms
|
||||
for (auto& room : _rooms) {
|
||||
room->setStop();
|
||||
}
|
||||
|
||||
std::cout << "[YourChat] Regular server stopped." << std::endl;
|
||||
}
|
||||
|
||||
void Server::run() {
|
||||
if (listen(_socket, 5) < 0) {
|
||||
std::cout << "listen not possible" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
timeval origTv;
|
||||
origTv.tv_sec = 5;
|
||||
origTv.tv_sec = 1; // Shorter timeout for more responsive shutdown
|
||||
origTv.tv_usec = 0;
|
||||
int _maxSd = _socket;
|
||||
std::set<int> activeSockets;
|
||||
@@ -90,7 +112,8 @@ namespace Yc {
|
||||
}
|
||||
}
|
||||
|
||||
if (select(_maxSd + 1, &fd, NULL, NULL, &tv) > 0) {
|
||||
int selectResult = select(_maxSd + 1, &fd, NULL, NULL, &tv);
|
||||
if (selectResult > 0) {
|
||||
// Neue Verbindung?
|
||||
if (FD_ISSET(_socket, &fd)) {
|
||||
std::thread(&Server::handleRequest, this).detach();
|
||||
@@ -110,6 +133,13 @@ namespace Yc {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (selectResult < 0) {
|
||||
if (errno == EINTR) {
|
||||
// Interrupted by signal, check if we should stop
|
||||
continue;
|
||||
}
|
||||
std::cerr << "[YourChat] select() error: " << strerror(errno) << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
// Aufgeräumte Sockets entfernen
|
||||
@@ -125,6 +155,7 @@ namespace Yc {
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "[YourChat] Server run loop exiting" << std::endl;
|
||||
}
|
||||
|
||||
std::vector<std::string> Server::roomList() {
|
||||
|
||||
@@ -15,7 +15,9 @@ namespace Yc {
|
||||
{
|
||||
public:
|
||||
Server(std::shared_ptr<Yc::Lib::Config> config, std::shared_ptr<Yc::Lib::Database> database);
|
||||
~Server();
|
||||
void run();
|
||||
void stop();
|
||||
std::vector<std::string> roomList();
|
||||
Json::Value jsonRoomList();
|
||||
bool roomAllowed(std::string roomName, std::string userName, std::string password);
|
||||
|
||||
@@ -52,14 +52,35 @@ void SSLServer::run() {
|
||||
}
|
||||
|
||||
void SSLServer::stop() {
|
||||
std::cout << "[YourChat] Stopping SSL Server..." << std::endl;
|
||||
_running = false;
|
||||
if (_context) lws_cancel_service(_context);
|
||||
if (_serverThread.joinable()) _serverThread.join();
|
||||
if (_messageThread.joinable()) _messageThread.join();
|
||||
|
||||
// Wake up the message queue thread
|
||||
_queueCV.notify_all();
|
||||
|
||||
// Cancel libwebsockets service
|
||||
if (_context) {
|
||||
lws_cancel_service(_context);
|
||||
}
|
||||
|
||||
// Wait for threads to finish
|
||||
if (_serverThread.joinable()) {
|
||||
std::cout << "[YourChat] Waiting for server thread to finish..." << std::endl;
|
||||
_serverThread.join();
|
||||
}
|
||||
|
||||
if (_messageThread.joinable()) {
|
||||
std::cout << "[YourChat] Waiting for message thread to finish..." << std::endl;
|
||||
_messageThread.join();
|
||||
}
|
||||
|
||||
// Clean up libwebsockets context
|
||||
if (_context) {
|
||||
lws_context_destroy(_context);
|
||||
_context = nullptr;
|
||||
}
|
||||
|
||||
std::cout << "[YourChat] SSL Server stopped." << std::endl;
|
||||
}
|
||||
|
||||
void SSLServer::startServer() {
|
||||
@@ -88,8 +109,15 @@ void SSLServer::startServer() {
|
||||
}
|
||||
|
||||
while (_running) {
|
||||
lws_service(_context, 50);
|
||||
// Use a shorter timeout to be more responsive to shutdown
|
||||
int ret = lws_service(_context, 10);
|
||||
if (ret < 0) {
|
||||
std::cerr << "[YourChat] lws_service returned error: " << ret << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "[YourChat] SSL Server thread exiting" << std::endl;
|
||||
}
|
||||
|
||||
void SSLServer::processMessageQueue() {
|
||||
@@ -97,7 +125,7 @@ void SSLServer::processMessageQueue() {
|
||||
std::unique_lock<std::mutex> lock(_queueMutex);
|
||||
_queueCV.wait(lock, [this](){ return !_messageQueue.empty() || !_running; });
|
||||
|
||||
while (!_messageQueue.empty()) {
|
||||
while (!_messageQueue.empty() && _running) {
|
||||
std::string msg = std::move(_messageQueue.front());
|
||||
_messageQueue.pop();
|
||||
lock.unlock();
|
||||
@@ -106,6 +134,7 @@ void SSLServer::processMessageQueue() {
|
||||
lock.lock();
|
||||
}
|
||||
}
|
||||
std::cout << "[YourChat] Message queue thread exiting" << std::endl;
|
||||
}
|
||||
|
||||
int SSLServer::wsCallback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
|
||||
|
||||
59
src/main.cpp
59
src/main.cpp
@@ -4,25 +4,64 @@
|
||||
#include "core/ssl_server.h"
|
||||
#include "lib/database.h"
|
||||
#include <iostream>
|
||||
#include <csignal>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
// Global flag for graceful shutdown
|
||||
std::atomic<bool> g_running{true};
|
||||
std::shared_ptr<Yc::Lib::SSLServer> g_sslServer = nullptr;
|
||||
std::shared_ptr<Yc::Lib::Server> g_server = nullptr;
|
||||
|
||||
// Signal handler for graceful shutdown
|
||||
void signalHandler(int signal) {
|
||||
std::cout << "\n[YourChat] Received signal " << signal << ", shutting down gracefully..." << std::endl;
|
||||
g_running = false;
|
||||
|
||||
if (g_sslServer) {
|
||||
g_sslServer->stop();
|
||||
}
|
||||
if (g_server) {
|
||||
g_server->stop();
|
||||
}
|
||||
}
|
||||
|
||||
// main function
|
||||
int main(int, char **) {
|
||||
// Set up signal handlers
|
||||
std::signal(SIGINT, signalHandler);
|
||||
std::signal(SIGTERM, signalHandler);
|
||||
|
||||
auto config = std::make_shared<Yc::Lib::Config>();
|
||||
auto database = std::make_shared<Yc::Lib::Database>(config);
|
||||
|
||||
// Check if SSL is enabled
|
||||
bool sslEnabled = config->value("server", "ssl_enabled").asBool();
|
||||
|
||||
if (sslEnabled) {
|
||||
std::cout << "[YourChat] Starting with SSL/TLS support" << std::endl;
|
||||
auto sslServer = std::make_shared<Yc::Lib::SSLServer>(config, database);
|
||||
sslServer->createRooms();
|
||||
sslServer->run();
|
||||
} else {
|
||||
std::cout << "[YourChat] Starting without SSL/TLS support" << std::endl;
|
||||
auto server = std::make_shared<Yc::Lib::Server>(config, database);
|
||||
server->createRooms(config->group("rooms"));
|
||||
server->run();
|
||||
try {
|
||||
if (sslEnabled) {
|
||||
std::cout << "[YourChat] Starting with SSL/TLS support" << std::endl;
|
||||
g_sslServer = std::make_shared<Yc::Lib::SSLServer>(config, database);
|
||||
g_sslServer->createRooms();
|
||||
g_sslServer->run();
|
||||
} else {
|
||||
std::cout << "[YourChat] Starting without SSL/TLS support" << std::endl;
|
||||
g_server = std::make_shared<Yc::Lib::Server>(config, database);
|
||||
g_server->createRooms(config->group("rooms"));
|
||||
g_server->run();
|
||||
}
|
||||
|
||||
// Main loop - wait for shutdown signal
|
||||
while (g_running) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
std::cout << "[YourChat] Shutdown complete." << std::endl;
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "[YourChat] Error: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user