2025-06-19 22:07:12 +08:00
|
|
|
#include "Server.h"
|
2025-06-14 09:27:50 +08:00
|
|
|
|
|
|
|
|
#include <QDateTime>
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
|
|
|
#include "InfoClient.h"
|
2025-06-25 17:06:30 +08:00
|
|
|
#include "InfoMsg.h"
|
2025-06-14 09:27:50 +08:00
|
|
|
#include "InfoPack.hpp"
|
|
|
|
|
|
2025-06-26 22:09:04 +08:00
|
|
|
#define NO_HEATBEAT_TIMEOUT (10)
|
2025-10-20 16:40:52 +08:00
|
|
|
#define MONITOR_HEART_SPED (10 * 2)
|
2025-06-26 22:09:04 +08:00
|
|
|
|
2025-06-14 09:27:50 +08:00
|
|
|
Server::Server(QObject* parent) : QTcpServer(parent)
|
|
|
|
|
{
|
|
|
|
|
monitorTimer_ = new QTimer(this);
|
|
|
|
|
connect(monitorTimer_, &QTimer::timeout, this, &Server::monitorClients);
|
2025-06-15 20:37:25 +08:00
|
|
|
connect(this, &Server::newConnection, this, &Server::onNewConnection);
|
2025-06-14 09:27:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Server::~Server()
|
|
|
|
|
{
|
|
|
|
|
stopServer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Server::startServer(quint16 port)
|
|
|
|
|
{
|
|
|
|
|
if (!listen(QHostAddress::Any, port)) {
|
|
|
|
|
qWarning() << "Server start failed:" << errorString();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-05 09:35:36 +08:00
|
|
|
qInfo() << "Server started on port" << serverPort();
|
2025-06-26 22:09:04 +08:00
|
|
|
monitorTimer_->start(MONITOR_HEART_SPED);
|
2025-06-15 20:37:25 +08:00
|
|
|
id_ = QString("0.0.0.0:%1").arg(serverPort());
|
2025-06-14 09:27:50 +08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Server::stopServer()
|
|
|
|
|
{
|
|
|
|
|
monitorTimer_->stop();
|
|
|
|
|
close();
|
|
|
|
|
|
|
|
|
|
QWriteLocker locker(&rwLock_);
|
|
|
|
|
for (auto& client : clients_) {
|
|
|
|
|
client->socket->disconnectFromHost();
|
|
|
|
|
client->socket->deleteLater();
|
|
|
|
|
}
|
|
|
|
|
clients_.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Server::onNewConnection()
|
|
|
|
|
{
|
|
|
|
|
QTcpSocket* clientSocket = nextPendingConnection();
|
2025-06-15 20:37:25 +08:00
|
|
|
|
|
|
|
|
QHostAddress peerAddress = clientSocket->peerAddress();
|
|
|
|
|
quint32 ipv4 = peerAddress.toIPv4Address();
|
|
|
|
|
QString ipStr = QHostAddress(ipv4).toString();
|
|
|
|
|
QString clientId = QString("%1:%2").arg(ipStr).arg(clientSocket->peerPort());
|
2025-06-14 09:27:50 +08:00
|
|
|
|
|
|
|
|
if (clients_.size() >= 100) {
|
|
|
|
|
qWarning() << "Client connection refused (max limit reached):" << clientId;
|
|
|
|
|
clientSocket->disconnectFromHost();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto client = QSharedPointer<ClientInfo>::create();
|
|
|
|
|
client->socket = clientSocket;
|
2025-06-15 20:37:25 +08:00
|
|
|
client->socket->setProperty("clientId", clientId);
|
2025-06-14 09:27:50 +08:00
|
|
|
client->id = clientId;
|
2025-06-25 10:54:04 +08:00
|
|
|
// client->connectTime = QDateTime::currentSecsSinceEpoch();
|
|
|
|
|
client->connectTime = QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000;
|
2025-06-14 09:27:50 +08:00
|
|
|
|
|
|
|
|
connect(clientSocket, &QTcpSocket::readyRead, this, &Server::onReadyRead);
|
|
|
|
|
connect(clientSocket, &QTcpSocket::disconnected, this, &Server::onClientDisconnected);
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
QWriteLocker locker(&rwLock_);
|
|
|
|
|
clients_.insert(clientId, client);
|
2025-11-09 11:53:59 +08:00
|
|
|
flowBackCount_[clientId] = 0;
|
2025-06-14 09:27:50 +08:00
|
|
|
}
|
|
|
|
|
|
2025-11-05 09:35:36 +08:00
|
|
|
qInfo() << "Client connected:" << clientId;
|
2025-06-14 09:27:50 +08:00
|
|
|
auto frame = QSharedPointer<FrameBuffer>::create();
|
|
|
|
|
frame->type = FBT_SER_MSG_YOURID;
|
2025-06-15 20:37:25 +08:00
|
|
|
frame->fid = id_;
|
2025-06-14 09:27:50 +08:00
|
|
|
frame->tid = clientId;
|
2025-06-15 20:37:25 +08:00
|
|
|
frame->data = clientId.toUtf8();
|
2025-06-14 09:27:50 +08:00
|
|
|
sendData(clientSocket, frame);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Server::onReadyRead()
|
|
|
|
|
{
|
|
|
|
|
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
|
|
|
|
|
if (!socket) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QSharedPointer<ClientInfo> client;
|
2025-06-28 09:00:38 +08:00
|
|
|
|
2025-06-14 09:27:50 +08:00
|
|
|
{
|
|
|
|
|
QReadLocker locker(&rwLock_);
|
2025-06-15 20:37:25 +08:00
|
|
|
client = clients_.value(socket->property("clientId").toString());
|
2025-06-14 09:27:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (client) {
|
2025-11-15 17:26:09 +08:00
|
|
|
if (client->buffer.size() > MAX_INVALID_PACKET_SIZE) {
|
|
|
|
|
auto mg = QString("Client %1 buffer size exceeded, XXXXX...").arg(client->id);
|
|
|
|
|
qWarning() << mg;
|
|
|
|
|
socket->disconnectFromHost();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-06-14 09:27:50 +08:00
|
|
|
client->buffer.append(socket->readAll());
|
|
|
|
|
processClientData(client);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Server::processClientData(QSharedPointer<ClientInfo> client)
|
|
|
|
|
{
|
|
|
|
|
while (true) {
|
|
|
|
|
auto frame = Protocol::ParseBuffer(client->buffer);
|
|
|
|
|
if (frame.isNull()) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
frame->fid = client->id;
|
|
|
|
|
if (frame->type <= 30) {
|
2025-11-09 11:53:59 +08:00
|
|
|
// frame->tid = "server";
|
2025-06-14 09:27:50 +08:00
|
|
|
replyRequest(client, frame);
|
|
|
|
|
} else {
|
|
|
|
|
if (!forwardData(client, frame)) {
|
|
|
|
|
qWarning() << "Failed to forward data from" << client->id << "to" << frame->tid;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-09 11:53:59 +08:00
|
|
|
bool Server::sendWithFlowCheck(QTcpSocket* fsoc, QTcpSocket* tsoc, QSharedPointer<FrameBuffer> frame)
|
|
|
|
|
{
|
|
|
|
|
auto flowLimit = [this](QTcpSocket* fsoc, BlockLevel aLevel) {
|
|
|
|
|
InfoMsg msg;
|
|
|
|
|
msg.mark = static_cast<qint32>(aLevel);
|
|
|
|
|
auto f = QSharedPointer<FrameBuffer>::create();
|
|
|
|
|
f->type = FBT_SER_FLOW_LIMIT;
|
|
|
|
|
f->data = infoPack<InfoMsg>(msg);
|
|
|
|
|
if (!sendData(fsoc, f)) {
|
|
|
|
|
qWarning() << "Failed to send flow limit message to" << fsoc->property("clientId").toString();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (flowBackCount_[fsoc->property("clientId").toString()] > FLOW_BACK_MULTIPLE) {
|
|
|
|
|
auto level = getBlockLevel(tsoc);
|
|
|
|
|
flowLimit(fsoc, level);
|
2025-11-15 17:26:09 +08:00
|
|
|
// qDebug() << "Flow back count exceeded, block level:" << level;
|
2025-11-09 11:53:59 +08:00
|
|
|
}
|
|
|
|
|
flowBackCount_[fsoc->property("clientId").toString()]++;
|
|
|
|
|
return sendData(tsoc, frame);
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-14 09:27:50 +08:00
|
|
|
bool Server::forwardData(QSharedPointer<ClientInfo> client, QSharedPointer<FrameBuffer> frame)
|
|
|
|
|
{
|
|
|
|
|
QSharedPointer<ClientInfo> targetClient;
|
2025-11-09 11:53:59 +08:00
|
|
|
QSharedPointer<ClientInfo> fromClient;
|
2025-06-19 22:07:12 +08:00
|
|
|
|
2025-06-14 09:27:50 +08:00
|
|
|
{
|
|
|
|
|
QReadLocker locker(&rwLock_);
|
|
|
|
|
targetClient = clients_.value(frame->tid);
|
2025-11-09 11:53:59 +08:00
|
|
|
fromClient = clients_.value(frame->fid);
|
2025-06-14 09:27:50 +08:00
|
|
|
}
|
|
|
|
|
|
2025-11-09 11:53:59 +08:00
|
|
|
if (targetClient && fromClient) {
|
|
|
|
|
return sendWithFlowCheck(fromClient->socket, targetClient->socket, frame);
|
2025-06-14 09:27:50 +08:00
|
|
|
} else {
|
|
|
|
|
auto errorFrame = QSharedPointer<FrameBuffer>::create();
|
|
|
|
|
errorFrame->type = FBT_SER_MSG_FORWARD_FAILED;
|
2025-06-15 20:37:25 +08:00
|
|
|
errorFrame->fid = id_;
|
2025-06-14 09:27:50 +08:00
|
|
|
errorFrame->tid = client->id;
|
|
|
|
|
errorFrame->data = QString("Target client %1 not found").arg(frame->tid).toUtf8();
|
|
|
|
|
return sendData(client->socket, errorFrame);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Server::replyRequest(QSharedPointer<ClientInfo> client, QSharedPointer<FrameBuffer> frame)
|
|
|
|
|
{
|
|
|
|
|
switch (frame->type) {
|
|
|
|
|
case FBT_SER_MSG_ASKCLIENTS: {
|
|
|
|
|
QByteArray clientList = getClients();
|
|
|
|
|
auto replyFrame = QSharedPointer<FrameBuffer>::create();
|
2025-06-15 20:37:25 +08:00
|
|
|
replyFrame->type = FBT_SER_MSG_ASKCLIENTS;
|
|
|
|
|
replyFrame->fid = id_;
|
2025-06-14 09:27:50 +08:00
|
|
|
replyFrame->tid = client->id;
|
|
|
|
|
replyFrame->data = clientList;
|
2025-06-15 20:37:25 +08:00
|
|
|
auto ret = sendData(client->socket, replyFrame);
|
2025-06-25 17:06:30 +08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case FBT_SER_MSG_HEARTBEAT: {
|
|
|
|
|
QSharedPointer<ClientInfo> cl;
|
|
|
|
|
{
|
|
|
|
|
QReadLocker locker(&rwLock_);
|
|
|
|
|
if (clients_.count(frame->fid)) {
|
|
|
|
|
cl = clients_.value(frame->fid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (cl) {
|
2025-11-09 11:53:59 +08:00
|
|
|
// qDebug() << "Client" << cl->id << "heartbeat received";
|
2025-06-25 17:06:30 +08:00
|
|
|
cl->connectTime = QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case FBT_SER_MSG_JUDGE_OTHER_ALIVE: {
|
|
|
|
|
QSharedPointer<ClientInfo> cl;
|
|
|
|
|
{
|
|
|
|
|
QReadLocker locker(&rwLock_);
|
|
|
|
|
if (clients_.count(frame->tid)) {
|
|
|
|
|
cl = clients_.value(frame->tid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!cl) {
|
|
|
|
|
auto rf = QSharedPointer<FrameBuffer>::create();
|
|
|
|
|
rf->type = FBT_SER_MSG_OFFLINE;
|
2025-11-09 14:26:39 +08:00
|
|
|
rf->fid = frame->tid;
|
2025-06-25 17:06:30 +08:00
|
|
|
rf->tid = frame->fid;
|
|
|
|
|
sendData(client->socket, rf);
|
|
|
|
|
}
|
2025-06-14 09:27:50 +08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
qWarning() << "Unknown request type:" << frame->type;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Server::sendData(QTcpSocket* socket, QSharedPointer<FrameBuffer> frame)
|
|
|
|
|
{
|
|
|
|
|
if (!socket || !socket->isOpen() || frame.isNull()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QByteArray data = Protocol::PackBuffer(frame);
|
|
|
|
|
if (data.isEmpty()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return socket->write(data) == data.size();
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-09 11:53:59 +08:00
|
|
|
BlockLevel Server::getBlockLevel(QTcpSocket* socket)
|
|
|
|
|
{
|
|
|
|
|
auto b = socket->bytesToWrite();
|
|
|
|
|
constexpr auto one = CHUNK_BUF_SIZE;
|
|
|
|
|
if (b > one * 1000) {
|
|
|
|
|
return BL_LEVEL_8;
|
|
|
|
|
}
|
|
|
|
|
if (b > one * 200) {
|
|
|
|
|
return BL_LEVEL_7;
|
|
|
|
|
}
|
|
|
|
|
if (b > one * 100) {
|
|
|
|
|
return BL_LEVEL_6;
|
|
|
|
|
}
|
|
|
|
|
if (b > one * 50) {
|
|
|
|
|
return BL_LEVEL_5;
|
|
|
|
|
}
|
|
|
|
|
if (b > one * 30) {
|
|
|
|
|
return BL_LEVEL_4;
|
|
|
|
|
}
|
|
|
|
|
if (b > one * 10) {
|
|
|
|
|
return BL_LEVEL_3;
|
|
|
|
|
}
|
|
|
|
|
if (b > one * 5) {
|
|
|
|
|
return BL_LEVEL_2;
|
|
|
|
|
}
|
|
|
|
|
if (b > one * 1) {
|
|
|
|
|
return BL_LEVEL_1;
|
|
|
|
|
}
|
|
|
|
|
return BL_LEVEL_NORMAL;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-28 09:00:38 +08:00
|
|
|
void Server::onClientDisconnected()
|
|
|
|
|
{
|
|
|
|
|
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
|
|
|
|
|
if (!socket) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString clientId = socket->property("clientId").toString();
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
QWriteLocker locker(&rwLock_);
|
|
|
|
|
if (clients_.count(clientId)) {
|
|
|
|
|
clients_.remove(clientId);
|
2025-11-09 11:53:59 +08:00
|
|
|
}
|
|
|
|
|
if (flowBackCount_.count(clientId)) {
|
|
|
|
|
flowBackCount_.remove(clientId);
|
2025-06-28 09:00:38 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-05 09:35:36 +08:00
|
|
|
qInfo() << "Client disconnected:" << __LINE__ << clientId;
|
2025-06-28 09:00:38 +08:00
|
|
|
socket->deleteLater();
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-14 09:27:50 +08:00
|
|
|
void Server::monitorClients()
|
|
|
|
|
{
|
2025-06-25 10:54:04 +08:00
|
|
|
qint64 now = QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000;
|
2025-06-28 09:00:38 +08:00
|
|
|
std::vector<QTcpSocket*> prepareRemove;
|
2025-06-14 09:27:50 +08:00
|
|
|
|
2025-06-28 09:00:38 +08:00
|
|
|
{
|
|
|
|
|
QReadLocker locker(&rwLock_);
|
|
|
|
|
for (auto& c : clients_) {
|
2025-10-22 17:10:22 +08:00
|
|
|
if ((now - c->connectTime) > NO_HEATBEAT_TIMEOUT) {
|
2025-06-28 09:00:38 +08:00
|
|
|
prepareRemove.push_back(c->socket);
|
|
|
|
|
}
|
2025-06-14 09:27:50 +08:00
|
|
|
}
|
|
|
|
|
}
|
2025-06-28 09:00:38 +08:00
|
|
|
for (const auto& s : prepareRemove) {
|
2025-11-05 09:35:36 +08:00
|
|
|
qInfo() << "Removing inactive client:" << s->property("clientId").toString();
|
2025-06-28 09:00:38 +08:00
|
|
|
s->disconnectFromHost();
|
|
|
|
|
}
|
2025-06-14 09:27:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QByteArray Server::getClients()
|
|
|
|
|
{
|
|
|
|
|
InfoClientVec infoClients;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
QReadLocker locker(&rwLock_);
|
|
|
|
|
for (auto& c : clients_) {
|
|
|
|
|
InfoClient infoClient;
|
|
|
|
|
infoClient.id = c->id;
|
|
|
|
|
infoClients.vec.append(infoClient);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto ret = infoPack<InfoClientVec>(infoClients);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|