Verbessere Shutdown-Logik und Ressourcenbereinigung in Server- und ChatRoom-Klassen
- Implementiere eine ordnungsgemäße Bereinigung von Server- und ChatRoom-Ressourcen beim Herunterfahren. - Aktualisiere die Destruktoren in `ChatRoom` und `Server`, um sicherzustellen, dass alle Benutzer-Threads gestoppt und aufgeräumt werden. - Füge Überprüfungen hinzu, um doppelte Stop-Vorgänge zu vermeiden und die Stabilität zu erhöhen. - Optimiere die Logging-Ausgaben für den Server-Stopp-Prozess zur besseren Nachverfolgbarkeit.
This commit is contained in:
@@ -37,7 +37,31 @@ namespace Yc
|
|||||||
thread = std::make_unique<std::thread>(&ChatRoom::run, this);
|
thread = std::make_unique<std::thread>(&ChatRoom::run, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatRoom::~ChatRoom() = default;
|
ChatRoom::~ChatRoom() {
|
||||||
|
setStop();
|
||||||
|
|
||||||
|
// Stop all users first
|
||||||
|
for (auto& user : _users) {
|
||||||
|
if (user) {
|
||||||
|
user->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for all user threads to finish
|
||||||
|
for (auto& user : _users) {
|
||||||
|
if (user && user->thread.joinable()) {
|
||||||
|
user->thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear users list
|
||||||
|
_users.clear();
|
||||||
|
|
||||||
|
// Now stop and join the room thread
|
||||||
|
if (thread && thread->joinable()) {
|
||||||
|
thread->join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ChatRoom::run()
|
void ChatRoom::run()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ namespace Yc
|
|||||||
std::string color() const;
|
std::string color() const;
|
||||||
void setParent(std::shared_ptr<ChatRoom> parent);
|
void setParent(std::shared_ptr<ChatRoom> parent);
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::thread thread;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<ChatRoom> _parent;
|
std::shared_ptr<ChatRoom> _parent;
|
||||||
Yc::Object::User _user;
|
Yc::Object::User _user;
|
||||||
@@ -56,7 +59,6 @@ namespace Yc
|
|||||||
int _socket;
|
int _socket;
|
||||||
std::string _token;
|
std::string _token;
|
||||||
bool _stop;
|
bool _stop;
|
||||||
std::thread thread;
|
|
||||||
|
|
||||||
void send(std::string out);
|
void send(std::string out);
|
||||||
void send(Json::Value out);
|
void send(Json::Value out);
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ namespace Yc {
|
|||||||
Server::Server(std::shared_ptr<Yc::Lib::Config> config, std::shared_ptr<Yc::Lib::Database> database) :
|
Server::Server(std::shared_ptr<Yc::Lib::Config> config, std::shared_ptr<Yc::Lib::Database> database) :
|
||||||
_config(std::move(config)),
|
_config(std::move(config)),
|
||||||
_database(std::move(database)),
|
_database(std::move(database)),
|
||||||
_stop(false) {
|
_stop(false),
|
||||||
|
_socket(-1) {
|
||||||
int port = 1235;
|
int port = 1235;
|
||||||
try {
|
try {
|
||||||
Json::Value p = _config->value("server", "port");
|
Json::Value p = _config->value("server", "port");
|
||||||
@@ -43,24 +44,39 @@ namespace Yc {
|
|||||||
// Fallback to IPv4
|
// Fallback to IPv4
|
||||||
close(_socket);
|
close(_socket);
|
||||||
_socket = socket(AF_INET, SOCK_STREAM, 0);
|
_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (_socket < 0) {
|
||||||
|
std::cout << "socket create failed" << std::endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
|
setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
|
||||||
flags = 1; setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
|
flags = 1; setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
|
||||||
ka = 1; setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka));
|
ka = 1; setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka));
|
||||||
struct sockaddr_in addr4{}; addr4.sin_family = AF_INET; addr4.sin_addr.s_addr = INADDR_ANY; addr4.sin_port = htons(port);
|
struct sockaddr_in addr4{}; addr4.sin_family = AF_INET; addr4.sin_addr.s_addr = INADDR_ANY; addr4.sin_port = htons(port);
|
||||||
if (bind(_socket, (struct sockaddr *)&addr4, sizeof(addr4)) != 0) {
|
if (bind(_socket, (struct sockaddr *)&addr4, sizeof(addr4)) != 0) {
|
||||||
std::cout << "bind not possible" << std::endl; exit(-1);
|
std::cout << "bind not possible on IPv4" << std::endl;
|
||||||
|
close(_socket);
|
||||||
|
_socket = -1;
|
||||||
|
exit(-1);
|
||||||
}
|
}
|
||||||
std::cout << "[YourChat] Server gestartet. Lausche auf Port " << port << " (IPv4)" << std::endl;
|
std::cout << "[YourChat] Server gestartet. Lausche auf Port " << port << " (IPv4)" << std::endl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Fallback to IPv4 directly
|
// Fallback to IPv4 directly
|
||||||
_socket = socket(AF_INET, SOCK_STREAM, 0);
|
_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (_socket < 0) { std::cout << "socket create failed" << std::endl; exit(-1);}
|
if (_socket < 0) {
|
||||||
|
std::cout << "socket create failed" << std::endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
|
setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
|
||||||
int flags = 1; setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
|
int flags = 1; setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
|
||||||
int ka = 1; setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka));
|
int ka = 1; setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka));
|
||||||
struct sockaddr_in addr4{}; addr4.sin_family = AF_INET; addr4.sin_addr.s_addr = INADDR_ANY; addr4.sin_port = htons(port);
|
struct sockaddr_in addr4{}; addr4.sin_family = AF_INET; addr4.sin_addr.s_addr = INADDR_ANY; addr4.sin_port = htons(port);
|
||||||
if (bind(_socket, (struct sockaddr *)&addr4, sizeof(addr4)) != 0) { std::cout << "bind not possible" << std::endl; exit(-1);}
|
if (bind(_socket, (struct sockaddr *)&addr4, sizeof(addr4)) != 0) {
|
||||||
|
std::cout << "bind not possible on IPv4" << std::endl;
|
||||||
|
close(_socket);
|
||||||
|
_socket = -1;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
std::cout << "[YourChat] Server gestartet. Lausche auf Port " << port << " (IPv4)" << std::endl;
|
std::cout << "[YourChat] Server gestartet. Lausche auf Port " << port << " (IPv4)" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,21 +90,35 @@ namespace Yc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Server::stop() {
|
void Server::stop() {
|
||||||
|
if (_stop) {
|
||||||
|
return; // Already stopped
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << "[YourChat] Stopping regular server..." << std::endl;
|
std::cout << "[YourChat] Stopping regular server..." << std::endl;
|
||||||
_stop = true;
|
_stop = true;
|
||||||
|
|
||||||
// Stop all rooms
|
// Stop all rooms
|
||||||
for (auto& room : _rooms) {
|
for (auto& room : _rooms) {
|
||||||
|
if (room) {
|
||||||
room->setStop();
|
room->setStop();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear rooms list to ensure proper cleanup order
|
||||||
|
_rooms.clear();
|
||||||
|
|
||||||
std::cout << "[YourChat] Regular server stopped." << std::endl;
|
std::cout << "[YourChat] Regular server stopped." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::run() {
|
void Server::run() {
|
||||||
|
if (_socket < 0) {
|
||||||
|
std::cout << "Invalid socket, cannot start server" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (listen(_socket, 5) < 0) {
|
if (listen(_socket, 5) < 0) {
|
||||||
std::cout << "listen not possible" << std::endl;
|
std::cout << "listen not possible: " << strerror(errno) << std::endl;
|
||||||
exit(-1);
|
return;
|
||||||
}
|
}
|
||||||
timeval origTv;
|
timeval origTv;
|
||||||
origTv.tv_sec = 1; // Shorter timeout for more responsive shutdown
|
origTv.tv_sec = 1; // Shorter timeout for more responsive shutdown
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ void SSLServer::run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SSLServer::stop() {
|
void SSLServer::stop() {
|
||||||
|
if (!_running) {
|
||||||
|
return; // Already stopped
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << "[YourChat] Stopping SSL Server..." << std::endl;
|
std::cout << "[YourChat] Stopping SSL Server..." << std::endl;
|
||||||
_running = false;
|
_running = false;
|
||||||
|
|
||||||
|
|||||||
10
src/main.cpp
10
src/main.cpp
@@ -57,6 +57,16 @@ int main(int, char **) {
|
|||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up servers before exit
|
||||||
|
if (g_sslServer) {
|
||||||
|
g_sslServer->stop();
|
||||||
|
g_sslServer.reset();
|
||||||
|
}
|
||||||
|
if (g_server) {
|
||||||
|
g_server->stop();
|
||||||
|
g_server.reset();
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << "[YourChat] Shutdown complete." << std::endl;
|
std::cout << "[YourChat] Shutdown complete." << std::endl;
|
||||||
|
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
|
|||||||
Reference in New Issue
Block a user