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 <arpa/inet.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
namespace Yc {
|
namespace Yc {
|
||||||
namespace Lib {
|
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() {
|
void Server::run() {
|
||||||
if (listen(_socket, 5) < 0) {
|
if (listen(_socket, 5) < 0) {
|
||||||
std::cout << "listen not possible" << std::endl;
|
std::cout << "listen not possible" << std::endl;
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
timeval origTv;
|
timeval origTv;
|
||||||
origTv.tv_sec = 5;
|
origTv.tv_sec = 1; // Shorter timeout for more responsive shutdown
|
||||||
origTv.tv_usec = 0;
|
origTv.tv_usec = 0;
|
||||||
int _maxSd = _socket;
|
int _maxSd = _socket;
|
||||||
std::set<int> activeSockets;
|
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?
|
// Neue Verbindung?
|
||||||
if (FD_ISSET(_socket, &fd)) {
|
if (FD_ISSET(_socket, &fd)) {
|
||||||
std::thread(&Server::handleRequest, this).detach();
|
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
|
// 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() {
|
std::vector<std::string> Server::roomList() {
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ namespace Yc {
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Server(std::shared_ptr<Yc::Lib::Config> config, std::shared_ptr<Yc::Lib::Database> database);
|
Server(std::shared_ptr<Yc::Lib::Config> config, std::shared_ptr<Yc::Lib::Database> database);
|
||||||
|
~Server();
|
||||||
void run();
|
void run();
|
||||||
|
void stop();
|
||||||
std::vector<std::string> roomList();
|
std::vector<std::string> roomList();
|
||||||
Json::Value jsonRoomList();
|
Json::Value jsonRoomList();
|
||||||
bool roomAllowed(std::string roomName, std::string userName, std::string password);
|
bool roomAllowed(std::string roomName, std::string userName, std::string password);
|
||||||
|
|||||||
@@ -52,14 +52,35 @@ void SSLServer::run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SSLServer::stop() {
|
void SSLServer::stop() {
|
||||||
|
std::cout << "[YourChat] Stopping SSL Server..." << std::endl;
|
||||||
_running = false;
|
_running = false;
|
||||||
if (_context) lws_cancel_service(_context);
|
|
||||||
if (_serverThread.joinable()) _serverThread.join();
|
// Wake up the message queue thread
|
||||||
if (_messageThread.joinable()) _messageThread.join();
|
_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) {
|
if (_context) {
|
||||||
lws_context_destroy(_context);
|
lws_context_destroy(_context);
|
||||||
_context = nullptr;
|
_context = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cout << "[YourChat] SSL Server stopped." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSLServer::startServer() {
|
void SSLServer::startServer() {
|
||||||
@@ -88,16 +109,23 @@ void SSLServer::startServer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (_running) {
|
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() {
|
void SSLServer::processMessageQueue() {
|
||||||
while (_running) {
|
while (_running) {
|
||||||
std::unique_lock<std::mutex> lock(_queueMutex);
|
std::unique_lock<std::mutex> lock(_queueMutex);
|
||||||
_queueCV.wait(lock, [this](){ return !_messageQueue.empty() || !_running; });
|
_queueCV.wait(lock, [this](){ return !_messageQueue.empty() || !_running; });
|
||||||
|
|
||||||
while (!_messageQueue.empty()) {
|
while (!_messageQueue.empty() && _running) {
|
||||||
std::string msg = std::move(_messageQueue.front());
|
std::string msg = std::move(_messageQueue.front());
|
||||||
_messageQueue.pop();
|
_messageQueue.pop();
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
@@ -106,6 +134,7 @@ void SSLServer::processMessageQueue() {
|
|||||||
lock.lock();
|
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) {
|
int SSLServer::wsCallback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
|
||||||
|
|||||||
51
src/main.cpp
51
src/main.cpp
@@ -4,25 +4,64 @@
|
|||||||
#include "core/ssl_server.h"
|
#include "core/ssl_server.h"
|
||||||
#include "lib/database.h"
|
#include "lib/database.h"
|
||||||
#include <iostream>
|
#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
|
// main function
|
||||||
int main(int, char **) {
|
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 config = std::make_shared<Yc::Lib::Config>();
|
||||||
auto database = std::make_shared<Yc::Lib::Database>(config);
|
auto database = std::make_shared<Yc::Lib::Database>(config);
|
||||||
|
|
||||||
// Check if SSL is enabled
|
// Check if SSL is enabled
|
||||||
bool sslEnabled = config->value("server", "ssl_enabled").asBool();
|
bool sslEnabled = config->value("server", "ssl_enabled").asBool();
|
||||||
|
|
||||||
|
try {
|
||||||
if (sslEnabled) {
|
if (sslEnabled) {
|
||||||
std::cout << "[YourChat] Starting with SSL/TLS support" << std::endl;
|
std::cout << "[YourChat] Starting with SSL/TLS support" << std::endl;
|
||||||
auto sslServer = std::make_shared<Yc::Lib::SSLServer>(config, database);
|
g_sslServer = std::make_shared<Yc::Lib::SSLServer>(config, database);
|
||||||
sslServer->createRooms();
|
g_sslServer->createRooms();
|
||||||
sslServer->run();
|
g_sslServer->run();
|
||||||
} else {
|
} else {
|
||||||
std::cout << "[YourChat] Starting without SSL/TLS support" << std::endl;
|
std::cout << "[YourChat] Starting without SSL/TLS support" << std::endl;
|
||||||
auto server = std::make_shared<Yc::Lib::Server>(config, database);
|
g_server = std::make_shared<Yc::Lib::Server>(config, database);
|
||||||
server->createRooms(config->group("rooms"));
|
g_server->createRooms(config->group("rooms"));
|
||||||
server->run();
|
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;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user