PIEthernet fix tcp-server close (properly delete all clients)
PIEthernet::stopThreadedListen() method decompose client to 2 implementations - server-side and client-side
This commit is contained in:
131
libs/client_server/piclientserver_server.cpp
Normal file
131
libs/client_server/piclientserver_server.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piclientserver_server.h"
|
||||
|
||||
#include "piclientserver_client.h"
|
||||
#include "piethernet.h"
|
||||
#include "piliterals_time.h"
|
||||
|
||||
|
||||
PIClientServer::Server::Server() {
|
||||
tcp_server = new PIEthernet(PIEthernet::TCP_Server);
|
||||
clean_thread = new PIThread();
|
||||
client_factory = [] { return new ServerClient(); };
|
||||
CONNECTL(tcp_server, newConnection, [this](PIEthernet * c) {
|
||||
PIMutexLocker guard(clients_mutex);
|
||||
if (clients.size_s() >= max_clients) {
|
||||
piCout << "Server::newConnection overflow clients count";
|
||||
delete c;
|
||||
return;
|
||||
}
|
||||
auto sc = client_factory();
|
||||
if (!sc) {
|
||||
piCout << "ClientFactory returns nullptr!";
|
||||
return;
|
||||
}
|
||||
sc->createForServer(c);
|
||||
newClient(sc);
|
||||
});
|
||||
|
||||
clean_thread->start(
|
||||
[this]() {
|
||||
PIVector<ServerClient *> to_delete;
|
||||
clients_mutex.lock();
|
||||
for (auto c: clients) {
|
||||
const PIEthernet * eth = c->getTCP();
|
||||
if (!eth) continue;
|
||||
if (eth->isConnected()) continue;
|
||||
c->can_write = false;
|
||||
to_delete << c;
|
||||
}
|
||||
for (auto c: to_delete)
|
||||
clients.removeOne(c);
|
||||
clients_mutex.unlock();
|
||||
for (auto c: to_delete) {
|
||||
c->aboutDelete();
|
||||
c->destroy();
|
||||
delete c;
|
||||
}
|
||||
},
|
||||
5_Hz);
|
||||
}
|
||||
|
||||
|
||||
PIClientServer::Server::~Server() {
|
||||
clean_thread->stopAndWait();
|
||||
piDeleteSafety(clean_thread);
|
||||
stopServer();
|
||||
for (auto c: clients) {
|
||||
c->aboutDelete();
|
||||
c->destroy();
|
||||
delete c;
|
||||
}
|
||||
piDeleteSafety(tcp_server);
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Server::listen(PINetworkAddress addr) {
|
||||
if (!tcp_server) return;
|
||||
stopServer();
|
||||
is_closing = false;
|
||||
tcp_server->listen(addr, true);
|
||||
// piCout << "Listen on" << addr.toString();
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Server::setMaxClients(int new_max_clients) {
|
||||
max_clients = new_max_clients;
|
||||
}
|
||||
|
||||
|
||||
int PIClientServer::Server::clientsCount() const {
|
||||
PIMutexLocker guard(clients_mutex);
|
||||
return clients.size_s();
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Server::forEachClient(std::function<void(ServerClient *)> func) {
|
||||
PIMutexLocker guard(clients_mutex);
|
||||
for (auto * c: clients) {
|
||||
func(c);
|
||||
if (is_closing) break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Server::enableSymmetricEncryption(const PIByteArray & key) {
|
||||
crypt_key = key;
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Server::stopServer() {
|
||||
if (!tcp_server) return;
|
||||
is_closing = true;
|
||||
tcp_server->stopThreadedListen();
|
||||
tcp_server->stopAndWait();
|
||||
}
|
||||
|
||||
|
||||
void PIClientServer::Server::newClient(ServerClient * c) {
|
||||
clients << c;
|
||||
c->enableSymmetricEncryption(crypt_key);
|
||||
c->tcp->startThreadedRead();
|
||||
c->connected();
|
||||
piCout << "New client";
|
||||
}
|
||||
Reference in New Issue
Block a user