communicate: basic server and client communicate.

This commit is contained in:
2025-06-15 20:37:25 +08:00
parent 7d123b2c06
commit 3538de7f4e
17 changed files with 147 additions and 62 deletions

View File

@@ -1,9 +1,14 @@
#include "ClientCore.h" #include "ClientCore.h"
#include <InfoMsg.h>
#include <InfoPack.hpp>
#include <QDebug> #include <QDebug>
ClientCore::ClientCore(QObject* parent) : QObject(parent) ClientCore::ClientCore(QObject* parent) : QObject(parent)
{ {
socket_ = new QTcpSocket(this);
connect(socket_, &QTcpSocket::readyRead, this, &ClientCore::onReadyRead);
connect(socket_, &QTcpSocket::disconnected, this, &ClientCore::onDisconnected);
} }
ClientCore::~ClientCore() ClientCore::~ClientCore()
@@ -22,6 +27,7 @@ bool ClientCore::Connect(const QString& ip, quint16 port)
qCritical() << QString(tr("%1:%2 connect failed...")).arg(ip).arg(port); qCritical() << QString(tr("%1:%2 connect failed...")).arg(ip).arg(port);
return false; return false;
} }
qInfo() << QString(tr("%1:%2 connected success.")).arg(ip).arg(port);
return true; return true;
} }
@@ -49,6 +55,21 @@ void ClientCore::onDisconnected()
void ClientCore::UseFrame(QSharedPointer<FrameBuffer> frame) void ClientCore::UseFrame(QSharedPointer<FrameBuffer> frame)
{ {
switch (frame->type) {
case FrameBufferType::FBT_SER_MSG_ASKCLIENTS: {
InfoClientVec info = infoUnpack<InfoClientVec>(frame->data);
clientsCall_(info);
break;
}
case FrameBufferType::FBT_SER_MSG_YOURID: {
ownID_ = frame->data;
qInfo() << QString(tr("own id: %1")).arg(ownID_);
break;
}
default:
qWarning() << QString(tr("unknown frame type: %1")).arg(frame->type);
break;
}
} }
bool ClientCore::Send(QSharedPointer<FrameBuffer> frame) bool ClientCore::Send(QSharedPointer<FrameBuffer> frame)
@@ -79,14 +100,17 @@ bool ClientCore::Send(const char* data, qint64 len)
void ClientCore::SetClientsCall(const std::function<void(const InfoClientVec& clients)>& call) void ClientCore::SetClientsCall(const std::function<void(const InfoClientVec& clients)>& call)
{ {
clientsCall_ = call;
} }
void ClientCore::SetPathCall(const std::function<void(const QString& path)>& call) void ClientCore::SetPathCall(const std::function<void(const QString& path)>& call)
{ {
pathCall_ = call;
} }
void ClientCore::SetFileCall(const std::function<void(const DirFileInfoVec& files)>& call) void ClientCore::SetFileCall(const std::function<void(const DirFileInfoVec& files)>& call)
{ {
fileCall_ = call;
} }
void ClientCore::SetRemoteID(const QString& id) void ClientCore::SetRemoteID(const QString& id)

View File

@@ -41,11 +41,14 @@ public:
public: public:
QMutex conMutex_; QMutex conMutex_;
QString ownID_;
QString remoteID_; QString remoteID_;
QTcpSocket* socket_; QTcpSocket* socket_;
QByteArray recvBuffer_; QByteArray recvBuffer_;
std::function<void(const QString& path)> pathCall_; std::function<void(const QString& path)> pathCall_;
std::function<void(const InfoClientVec& clients)> clientsCall_;
std::function<void(const DirFileInfoVec& files)> fileCall_;
}; };
#endif // CLIENTCORE_H #endif // CLIENTCORE_H

View File

@@ -12,11 +12,11 @@ class Compare : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit Compare(QWidget *parent = nullptr); explicit Compare(QWidget* parent = nullptr);
~Compare(); ~Compare();
private: private:
Ui::Compare *ui; Ui::Compare* ui;
}; };
#endif // COMPARECONTROL_H #endif // COMPARECONTROL_H

View File

@@ -4,11 +4,10 @@
#include <InfoPack.hpp> #include <InfoPack.hpp>
#include <future> #include <future>
#include "Control/LogControl.h"
#include "GuiUtil/Public.h" #include "GuiUtil/Public.h"
#include "ui_ConnectControl.h" #include "ui_ConnectControl.h"
Connecter::Connecter(QWidget* parent) : QWidget(parent), ui(new Ui::Connecter) Connecter::Connecter(QWidget* parent) : QWidget(parent), ui(new Ui::Connecter), th_(nullptr)
{ {
ui->setupUi(this); ui->setupUi(this);
InitControl(); InitControl();
@@ -16,9 +15,6 @@ Connecter::Connecter(QWidget* parent) : QWidget(parent), ui(new Ui::Connecter)
Connecter::~Connecter() Connecter::~Connecter()
{ {
if (thConnect_.joinable()) {
thConnect_.join();
}
delete ui; delete ui;
} }
@@ -28,11 +24,6 @@ void Connecter::SetClientCore(ClientCore* clientCore)
clientCore_->SetClientsCall([this](const InfoClientVec& clients) { HandleClients(clients); }); clientCore_->SetClientsCall([this](const InfoClientVec& clients) { HandleClients(clients); });
} }
void Connecter::SetLogPrint(LogPrint* log)
{
log_ = log;
}
void Connecter::SetRemoteCall(const std::function<void(const QString& id)>& call) void Connecter::SetRemoteCall(const std::function<void(const QString& id)>& call)
{ {
remoteCall_ = call; remoteCall_ = call;
@@ -42,7 +33,7 @@ void Connecter::HandleClients(const InfoClientVec& clients)
{ {
model_->removeRows(0, ui->listView->model()->rowCount()); model_->removeRows(0, ui->listView->model()->rowCount());
for (const auto& client : clients.vec) { for (const auto& client : clients.vec) {
auto* item = new QStandardItem(client.name); auto* item = new QStandardItem(client.id);
model_->appendRow(item); model_->appendRow(item);
} }
} }
@@ -55,19 +46,30 @@ void Connecter::Connect()
FTCommon::msg(this, tr("IP or Port is empty.")); FTCommon::msg(this, tr("IP or Port is empty."));
return; return;
} }
auto task = [this, ip, port]() {
emit sendConnect(ConnectState::CS_CONNECTING); if (th_) {
connceted_ = clientCore_->Connect(ip, port.toInt()); if (th_->isRunning()) {
if (connceted_) { th_->quit();
emit sendConnect(ConnectState::CS_CONNECTED); th_->wait(1000);
} else {
emit sendConnect(ConnectState::CS_DISCONNECT);
} }
}; delete th_;
if (thConnect_.joinable()) {
thConnect_.join();
} }
thConnect_ = std::thread(task);
auto* worker = new ConnectWorker(clientCore_, nullptr);
th_ = new QThread();
worker->moveToThread(th_);
clientCore_->moveToThread(th_);
connect(th_, &QThread::started,
[this, worker, ip, port]() { worker->doConnect(ip, port.toInt(), this->parent()->thread()); });
connect(worker, &ConnectWorker::connecting, this, [this]() { setState(ConnectState::CS_CONNECTING); });
connect(worker, &ConnectWorker::connectResult, this, [this](bool success) {
emit sendConnect(success ? ConnectState::CS_CONNECTED : ConnectState::CS_DISCONNECT);
th_->quit();
});
connect(th_, &QThread::finished, worker, &QObject::deleteLater);
connect(th_, &QThread::finished, th_, &QObject::deleteLater);
th_->start();
} }
void Connecter::setState(ConnectState cs) void Connecter::setState(ConnectState cs)
@@ -76,7 +78,7 @@ void Connecter::setState(ConnectState cs)
case CS_CONNECTING: case CS_CONNECTING:
ui->btnConnect->setEnabled(false); ui->btnConnect->setEnabled(false);
ui->btnDisconnect->setEnabled(false); ui->btnDisconnect->setEnabled(false);
log_->Info(tr("Connecting...")); qInfo() << QString(tr("Connecting..."));
break; break;
case CS_CONNECTED: case CS_CONNECTED:
ui->btnConnect->setEnabled(false); ui->btnConnect->setEnabled(false);

View File

@@ -17,7 +17,6 @@ enum ConnectState {
CS_CONNECTED, CS_CONNECTED,
}; };
class LogPrint;
class Connecter : public QWidget class Connecter : public QWidget
{ {
Q_OBJECT Q_OBJECT
@@ -28,7 +27,6 @@ public:
public: public:
void SetClientCore(ClientCore* clientCore); void SetClientCore(ClientCore* clientCore);
void SetLogPrint(LogPrint* log);
void SetRemoteCall(const std::function<void(const QString& id)>& call); void SetRemoteCall(const std::function<void(const QString& id)>& call);
void HandleClients(const InfoClientVec& clients); void HandleClients(const InfoClientVec& clients);
@@ -44,10 +42,7 @@ private:
std::string getCurClient(); std::string getCurClient();
private: private:
std::thread thConnect_;
Ui::Connecter* ui; Ui::Connecter* ui;
LogPrint* log_;
bool thRun_{false};
bool connceted_{false}; bool connceted_{false};
std::thread thContext_; std::thread thContext_;
std::function<void(const QString& id)> remoteCall_; std::function<void(const QString& id)> remoteCall_;
@@ -55,7 +50,35 @@ private:
private: private:
QMenu* menu_; QMenu* menu_;
QThread* th_;
QThread* mainTh_;
QStandardItemModel* model_; QStandardItemModel* model_;
}; };
class ConnectWorker : public QObject
{
Q_OBJECT
public:
explicit ConnectWorker(ClientCore* clientCore, QObject* parent = nullptr)
: QObject(parent), clientCore_(clientCore)
{
}
public slots:
void doConnect(const QString& ip, int port, QThread* parentThread)
{
emit connecting();
bool connected = clientCore_->Connect(ip, port);
clientCore_->moveToThread(parentThread);
emit connectResult(connected);
}
signals:
void connectResult(bool success);
void connecting();
private:
ClientCore* clientCore_;
};
#endif // CONNECTCONTROL_H #endif // CONNECTCONTROL_H

View File

@@ -8,7 +8,6 @@
#include <QTableWidgetItem> #include <QTableWidgetItem>
#include <RemoteFile.h> #include <RemoteFile.h>
#include "LogControl.h"
#include "ui_FileControl.h" #include "ui_FileControl.h"
FileManager::FileManager(QWidget* parent) : QWidget(parent), ui(new Ui::FileManager) FileManager::FileManager(QWidget* parent) : QWidget(parent), ui(new Ui::FileManager)
@@ -38,11 +37,6 @@ void FileManager::SetModeStr(const QString& modeStr, int type, ClientCore* clien
} }
} }
void FileManager::SetLogPrint(LogPrint* log)
{
log_ = log;
}
void FileManager::InitControl() void FileManager::InitControl()
{ {
QStringList headers; QStringList headers;

View File

@@ -10,7 +10,6 @@ namespace Ui {
class FileManager; class FileManager;
} }
class LogPrint;
class FileManager : public QWidget class FileManager : public QWidget
{ {
Q_OBJECT Q_OBJECT
@@ -21,7 +20,6 @@ public:
public: public:
void SetModeStr(const QString& modeStr, int type = 0, ClientCore* clientCore = nullptr); void SetModeStr(const QString& modeStr, int type = 0, ClientCore* clientCore = nullptr);
void SetLogPrint(LogPrint* log);
private: private:
void InitControl(); void InitControl();
@@ -36,7 +34,6 @@ private:
private: private:
Ui::FileManager* ui; Ui::FileManager* ui;
LogPrint* log_;
QString curRoot_; QString curRoot_;
std::shared_ptr<DirFileHelper> fileHelper_; std::shared_ptr<DirFileHelper> fileHelper_;
}; };

View File

@@ -43,7 +43,7 @@ void LogPrint::Info(const QString& message)
} }
void LogPrint::Warn(const QString& message) void LogPrint::Warn(const QString& message)
{ {
Print(message, Qt::yellow); Print(message, Qt::gray);
} }
void LogPrint::Error(const QString& message) void LogPrint::Error(const QString& message)
{ {

View File

@@ -13,4 +13,4 @@ public:
static QString GetAppPath(); static QString GetAppPath();
}; };
#endif // PUBLIC_H #endif // PUBLIC_H

View File

@@ -4,6 +4,8 @@
#include "./ui_frelayGUI.h" #include "./ui_frelayGUI.h"
static LogPrint* logPrint = nullptr;
frelayGUI::frelayGUI(QWidget* parent) : QMainWindow(parent), ui(new Ui::frelayGUI) frelayGUI::frelayGUI(QWidget* parent) : QMainWindow(parent), ui(new Ui::frelayGUI)
{ {
ui->setupUi(this); ui->setupUi(this);
@@ -20,21 +22,17 @@ frelayGUI::~frelayGUI()
void frelayGUI::InitControl() void frelayGUI::InitControl()
{ {
log_ = new LogPrint(this); logPrint = new LogPrint(this);
clientCore_ = new ClientCore();
clientCore_ = new ClientCore(this);
connecter_ = new Connecter(this); connecter_ = new Connecter(this);
connecter_->SetClientCore(clientCore_); connecter_->SetClientCore(clientCore_);
connecter_->SetLogPrint(log_);
connecter_->SetRemoteCall([this](const QString& id) { clientCore_->SetRemoteID(id); }); connecter_->SetRemoteCall([this](const QString& id) { clientCore_->SetRemoteID(id); });
localFile_ = new FileManager(this); localFile_ = new FileManager(this);
remoteFile_ = new FileManager(this); remoteFile_ = new FileManager(this);
localFile_->SetModeStr(tr("Local:")); localFile_->SetModeStr(tr("Local:"));
remoteFile_->SetModeStr(tr("Remote:"), 1, clientCore_); remoteFile_->SetModeStr(tr("Remote:"), 1, clientCore_);
localFile_->SetLogPrint(log_);
remoteFile_->SetLogPrint(log_);
tabWidget_ = new QTabWidget(this); tabWidget_ = new QTabWidget(this);
} }
@@ -57,7 +55,7 @@ void frelayGUI::ControlLayout()
sTop->addWidget(tabWidget_); sTop->addWidget(tabWidget_);
sTop->addWidget(connecter_); sTop->addWidget(connecter_);
tabWidget_->addTab(log_, tr("Log")); tabWidget_->addTab(logPrint, tr("Log"));
sFile->addWidget(localFile_); sFile->addWidget(localFile_);
sFile->addWidget(remoteFile_); sFile->addWidget(remoteFile_);
@@ -67,6 +65,30 @@ void frelayGUI::ControlLayout()
setCentralWidget(splitter); setCentralWidget(splitter);
} }
void frelayGUI::ControlMsgHander(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
Q_UNUSED(context);
switch (type) {
case QtDebugMsg:
logPrint->Debug(msg);
break;
case QtInfoMsg:
logPrint->Info(msg);
break;
case QtWarningMsg:
logPrint->Warn(msg);
break;
case QtCriticalMsg:
case QtFatalMsg:
logPrint->Error(msg);
break;
default:
logPrint->Error("Unknown QtMsgType type.");
break;
}
}
void frelayGUI::closeEvent(QCloseEvent* event) void frelayGUI::closeEvent(QCloseEvent* event)
{ {
QMainWindow::closeEvent(event); QMainWindow::closeEvent(event);

View File

@@ -30,12 +30,14 @@ private:
void ControlSignal(); void ControlSignal();
void ControlLayout(); void ControlLayout();
public:
static void ControlMsgHander(QtMsgType type, const QMessageLogContext& context, const QString& msg);
protected: protected:
void closeEvent(QCloseEvent* event) override; void closeEvent(QCloseEvent* event) override;
private: private:
Ui::frelayGUI* ui; Ui::frelayGUI* ui;
LogPrint* log_;
QTabWidget* tabWidget_; QTabWidget* tabWidget_;
Connecter* connecter_; Connecter* connecter_;
FileManager* localFile_; FileManager* localFile_;

View File

@@ -7,6 +7,8 @@ int main(int argc, char* argv[])
{ {
QApplication a(argc, argv); QApplication a(argc, argv);
qInstallMessageHandler(frelayGUI::ControlMsgHander);
#ifdef _WIN32 #ifdef _WIN32
QFont font("Microsoft YaHei", 9); QFont font("Microsoft YaHei", 9);
a.setFont(font); a.setFont(font);

View File

@@ -13,5 +13,5 @@ find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Network)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Network) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Network)
add_executable(frelayServer Server.h Server.cpp main.cpp) add_executable(frelayServer Server.h Server.cpp main.cpp)
target_link_libraries(frelayServer PRIVATE Protocol) target_link_libraries(frelayServer PRIVATE Protocol Util)
target_link_libraries(frelayServer PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Network) target_link_libraries(frelayServer PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Network)

View File

@@ -10,6 +10,7 @@ Server::Server(QObject* parent) : QTcpServer(parent)
{ {
monitorTimer_ = new QTimer(this); monitorTimer_ = new QTimer(this);
connect(monitorTimer_, &QTimer::timeout, this, &Server::monitorClients); connect(monitorTimer_, &QTimer::timeout, this, &Server::monitorClients);
connect(this, &Server::newConnection, this, &Server::onNewConnection);
} }
Server::~Server() Server::~Server()
@@ -26,6 +27,7 @@ bool Server::startServer(quint16 port)
qDebug() << "Server started on port" << serverPort(); qDebug() << "Server started on port" << serverPort();
monitorTimer_->start(30000); monitorTimer_->start(30000);
id_ = QString("0.0.0.0:%1").arg(serverPort());
return true; return true;
} }
@@ -45,7 +47,11 @@ void Server::stopServer()
void Server::onNewConnection() void Server::onNewConnection()
{ {
QTcpSocket* clientSocket = nextPendingConnection(); QTcpSocket* clientSocket = nextPendingConnection();
QString clientId = QString("%1:%2").arg(clientSocket->peerAddress().toString()).arg(clientSocket->peerPort());
QHostAddress peerAddress = clientSocket->peerAddress();
quint32 ipv4 = peerAddress.toIPv4Address();
QString ipStr = QHostAddress(ipv4).toString();
QString clientId = QString("%1:%2").arg(ipStr).arg(clientSocket->peerPort());
if (clients_.size() >= 100) { if (clients_.size() >= 100) {
qWarning() << "Client connection refused (max limit reached):" << clientId; qWarning() << "Client connection refused (max limit reached):" << clientId;
@@ -55,6 +61,7 @@ void Server::onNewConnection()
auto client = QSharedPointer<ClientInfo>::create(); auto client = QSharedPointer<ClientInfo>::create();
client->socket = clientSocket; client->socket = clientSocket;
client->socket->setProperty("clientId", clientId);
client->id = clientId; client->id = clientId;
client->connectTime = QDateTime::currentSecsSinceEpoch(); client->connectTime = QDateTime::currentSecsSinceEpoch();
@@ -69,9 +76,9 @@ void Server::onNewConnection()
qDebug() << "Client connected:" << clientId; qDebug() << "Client connected:" << clientId;
auto frame = QSharedPointer<FrameBuffer>::create(); auto frame = QSharedPointer<FrameBuffer>::create();
frame->type = FBT_SER_MSG_YOURID; frame->type = FBT_SER_MSG_YOURID;
frame->fid = "server"; frame->fid = id_;
frame->tid = clientId; frame->tid = clientId;
frame->data = QString("Welcome client %1").arg(clientId).toUtf8(); frame->data = clientId.toUtf8();
sendData(clientSocket, frame); sendData(clientSocket, frame);
} }
@@ -82,7 +89,10 @@ void Server::onClientDisconnected()
return; return;
} }
QString clientId = QString("%1:%2").arg(socket->peerAddress().toString()).arg(socket->peerPort()); QHostAddress peerAddress = socket->peerAddress();
quint32 ipv4 = peerAddress.toIPv4Address();
QString ipStr = QHostAddress(ipv4).toString();
QString clientId = QString("%1:%2").arg(ipStr).arg(socket->peerPort());
{ {
QWriteLocker locker(&rwLock_); QWriteLocker locker(&rwLock_);
@@ -100,12 +110,10 @@ void Server::onReadyRead()
return; return;
} }
QString clientId = QString("%1:%2").arg(socket->peerAddress().toString()).arg(socket->peerPort());
QSharedPointer<ClientInfo> client; QSharedPointer<ClientInfo> client;
{ {
QReadLocker locker(&rwLock_); QReadLocker locker(&rwLock_);
client = clients_.value(clientId); client = clients_.value(socket->property("clientId").toString());
} }
if (client) { if (client) {
@@ -147,7 +155,7 @@ bool Server::forwardData(QSharedPointer<ClientInfo> client, QSharedPointer<Frame
} else { } else {
auto errorFrame = QSharedPointer<FrameBuffer>::create(); auto errorFrame = QSharedPointer<FrameBuffer>::create();
errorFrame->type = FBT_SER_MSG_FORWARD_FAILED; errorFrame->type = FBT_SER_MSG_FORWARD_FAILED;
errorFrame->fid = "server"; errorFrame->fid = id_;
errorFrame->tid = client->id; errorFrame->tid = client->id;
errorFrame->data = QString("Target client %1 not found").arg(frame->tid).toUtf8(); errorFrame->data = QString("Target client %1 not found").arg(frame->tid).toUtf8();
return sendData(client->socket, errorFrame); return sendData(client->socket, errorFrame);
@@ -160,11 +168,12 @@ void Server::replyRequest(QSharedPointer<ClientInfo> client, QSharedPointer<Fram
case FBT_SER_MSG_ASKCLIENTS: { case FBT_SER_MSG_ASKCLIENTS: {
QByteArray clientList = getClients(); QByteArray clientList = getClients();
auto replyFrame = QSharedPointer<FrameBuffer>::create(); auto replyFrame = QSharedPointer<FrameBuffer>::create();
replyFrame->type = FBT_SER_MSG_RESPONSE; replyFrame->type = FBT_SER_MSG_ASKCLIENTS;
replyFrame->fid = "server"; replyFrame->fid = id_;
replyFrame->tid = client->id; replyFrame->tid = client->id;
replyFrame->data = clientList; replyFrame->data = clientList;
sendData(client->socket, replyFrame); auto ret = sendData(client->socket, replyFrame);
qDebug() << "Reply client list:" << client->id << ret;
break; break;
} }
default: default:

View File

@@ -42,6 +42,7 @@ private:
void replyRequest(QSharedPointer<ClientInfo> client, QSharedPointer<FrameBuffer> frame); void replyRequest(QSharedPointer<ClientInfo> client, QSharedPointer<FrameBuffer> frame);
bool sendData(QTcpSocket* socket, QSharedPointer<FrameBuffer> frame); bool sendData(QTcpSocket* socket, QSharedPointer<FrameBuffer> frame);
QString id_;
QMap<QString, QSharedPointer<ClientInfo>> clients_; QMap<QString, QSharedPointer<ClientInfo>> clients_;
QReadWriteLock rwLock_; QReadWriteLock rwLock_;
QTimer* monitorTimer_; QTimer* monitorTimer_;

View File

@@ -1,11 +1,15 @@
#include <QCoreApplication> #include <QCoreApplication>
#include "Server.h" #include "Server.h"
#include <Util.h>
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
QCoreApplication app(argc, argv); QCoreApplication app(argc, argv);
Util::InitLogger("frelayServer.log", "frelayServer");
qInstallMessageHandler(Util::ConsoleMsgHander);
Server server; Server server;
if (!server.startServer(9009)) { if (!server.startServer(9009)) {
return 1; return 1;

View File

@@ -66,8 +66,10 @@ QString DirFileHelper::GetErr() const
void DirFileHelper::registerPathCall(const std::function<void(const QString& path)>& call) void DirFileHelper::registerPathCall(const std::function<void(const QString& path)>& call)
{ {
pathCall_ = call;
} }
void DirFileHelper::registerFileCall(const std::function<void(const DirFileInfoVec& vec)>& call) void DirFileHelper::registerFileCall(const std::function<void(const DirFileInfoVec& vec)>& call)
{ {
fileCall_ = call;
} }