Platform Architecture & Module Boundaries

01. 平台架构与模块边界

以桌面客户端、中心服务与独立启动器为三条运行主线,说明各模块的启动入口、对象所有权和协议衔接方式。

6 个核心函数6 个重点文件基于当前工程源码

模块职责

以桌面客户端、中心服务与独立启动器为三条运行主线,说明各模块的启动入口、对象所有权和协议衔接方式。

重点文件

调用链

  1. 1应用进程启动
  2. 2构造业务入口对象
  3. 3建立网络与信号连接
  4. 4解析平台协议链接
  5. 5进入 Qt / 服务端事件循环
Launcher 进程入口

main

初始化 Qt 应用元数据,创建 LauncherWindow,并在启动参数中识别 p2plauncher:// 深链接。

main.cpp · L7–L29
原型int main(int argc, char *argv[])

调用时机

Launcher 可执行程序启动时调用。

返回说明

返回 Qt 事件循环退出码。

参数

参数说明
argc命令行参数数量
argv命令行参数数组

执行流程

  1. 创建 QApplication
  2. 设置组织、应用名称和版本
  3. 显示主窗口
  4. 解析首个深链接参数
  5. 进入事件循环

工程说明

入口保持轻量,只承担进程级初始化与启动参数转交。

关联接口

查看完整实现
main.cpp
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QCoreApplication::setOrganizationName("P2PPlatform");
    QCoreApplication::setApplicationName("P2P Platform Launcher");
    QCoreApplication::setApplicationVersion("1.0.0");

    LauncherWindow w;
    w.show();

    QStringList args = QCoreApplication::arguments();

    if (args.size() >= 2) {
        QString deepLink = args.at(1);

        if (deepLink.startsWith("p2plauncher://")) {
            w.handleDeepLink(deepLink);
        }
    }

    return a.exec();
}
Qt 主客户端

MainWindow::MainWindow

构建登录页与工作台,初始化 ClientLogic、更新管理器和全局信号连接。

mainwindow.cpp · L71–L119
原型MainWindow::MainWindow(QWidget *parent) : QWidget(parent)

调用时机

主客户端创建主窗口时调用。

返回说明

构造函数无返回值。

参数

参数说明
parent父级 QWidget,可为空

执行流程

  1. 应用统一控件样式
  2. 创建 ClientLogic
  3. 构建 QStackedWidget
  4. 初始化登录页与工作台
  5. 绑定业务信号
  6. 延迟检查更新

工程说明

ClientLogic 作为 MainWindow 子对象,由 Qt 对象树管理生命周期。

关联接口

查看完整实现
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent)
{
    resize(430, 720);
    setMinimumSize(390, 640);
    setWindowTitle(QString("P2P Platform 客户端  v%1").arg(APP_VERSION));

    qApp->setStyleSheet(
        "QWidget { font-family: 'Microsoft YaHei UI', 'Segoe UI'; color: #111827; }"
        "QLineEdit { min-height: 34px; border: 1px solid #d1d5db; border-radius: 8px; padding: 6px 10px; background: white; }"
        "QLineEdit:focus { border: 1px solid #2563eb; }"
        "QPushButton { min-height: 32px; border-radius: 8px; padding: 6px 12px; border: 1px solid #d1d5db; background: #ffffff; }"
        "QPushButton:hover { background: #eff6ff; border-color: #93c5fd; }"
        "QPushButton:disabled { color: #9ca3af; background: #f3f4f6; }"
        "QTabWidget::pane { border: 1px solid #e5e7eb; border-radius: 10px; background: #ffffff; }"
        "QTabBar::tab { padding: 8px 14px; margin: 3px; border-radius: 8px; background: #f3f4f6; }"
        "QTabBar::tab:selected { background: #2563eb; color: white; }"
        "QListWidget { background: #ffffff; border: 1px solid #e5e7eb; border-radius: 10px; }"
        "QListWidget::item:selected { background: #dbeafe; color: #111827; }"
    );

    logic = new ClientLogic(this);

    stackedWidget = new QStackedWidget(this);

    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    mainLayout->setContentsMargins(0, 0, 0, 0);
    mainLayout->addWidget(stackedWidget);

    setupLoginPage();
    setupDashboardPage();
    setupUpdateManager();

    stackedWidget->addWidget(loginPage);
    stackedWidget->addWidget(dashboardPage);
    stackedWidget->setCurrentIndex(0);

    bindLogicSignals();

    QTimer::singleShot(2000, this, [=]() {
        if (updateManager) {
            updateManager->checkUpdate(false);
        }
    });
}
客户端业务适配层

ClientLogic::ClientLogic

初始化网络管理器和草稿管理器,并将网络响应统一接入业务分发函数。

clientlogic.cpp · L19–L49
原型ClientLogic::ClientLogic(QObject *parent) : QObject(parent)

调用时机

MainWindow 初始化客户端业务层时调用。

返回说明

构造函数无返回值。

参数

参数说明
parent父级 QObject

执行流程

  1. 创建 NetworkManager
  2. 创建 DraftManager
  3. 连接网络响应信号
  4. 连接运行日志信号

工程说明

该对象承担 UI 与网络协议之间的稳定边界。

关联接口

查看完整实现
clientlogic.cpp
ClientLogic::ClientLogic(QObject *parent) : QObject(parent)
{
    netManager = new NetworkManager(this);
    draftManager = new DraftManager(this);

    connect(netManager, &NetworkManager::sigJsonReceived,
            this, &ClientLogic::handleNetworkResponse);

    connect(netManager, &NetworkManager::sigLogMessage,
            this,
            [this](const QString& msg) {
                emitUiLog(msg);
            });

    connect(netManager, &NetworkManager::sigPunchSuccess,
            this, &ClientLogic::sigPunchSuccess);

    m_heartbeatTimer = new QTimer(this);
    m_heartbeatTimer->setInterval(m_heartbeatIntervalMs);
    connect(m_heartbeatTimer, &QTimer::timeout,
            this, &ClientLogic::sendHeartbeat);
}
中心服务网络层

NetworkServer::NetworkServer

初始化 UDP 服务、epoll、线程池和 BusinessHandler,为主循环准备运行资源。

network_server.cpp · L108–L116
原型NetworkServer::NetworkServer(int port, int thread_count) : pool(thread_count, 4096, "business-pool")

调用时机

中心服务进程创建网络服务器时调用。

返回说明

构造函数无返回值。

参数

参数说明
portUDP 业务端口
thread_count业务工作线程数量

执行流程

  1. 初始化线程池
  2. 创建 UDP socket
  3. 建立 epoll
  4. 创建 BusinessHandler

工程说明

网络接收与业务执行分离,避免耗时业务阻塞收包。

关联接口

查看完整实现
network_server.cpp
NetworkServer::NetworkServer(int port, int thread_count)
    : pool(thread_count, 4096, "business-pool")
{
    handler = new BusinessHandler(this);

    if (!initUdpServer(port)) {
        std::cerr << "❌ [UDP 服务器] 初始化失败。\n";
    }
}
组件交付与启动器

LauncherWindow::LauncherWindow

创建网络访问管理器、搭建启动器 UI,并同步客户端与游戏组件清单。

launcherwindow.cpp · L34–L42
原型LauncherWindow::LauncherWindow(QWidget *parent) : QMainWindow(parent)

调用时机

Launcher 主窗口创建时调用。

返回说明

构造函数无返回值。

参数

参数说明
parent父级 QWidget

执行流程

  1. 创建网络管理对象
  2. 初始化 UI
  3. 拉取版本与组件清单

工程说明

启动器与主客户端独立发布,减少通信主程序的组件耦合。

关联接口

查看完整实现
launcherwindow.cpp
LauncherWindow::LauncherWindow(QWidget *parent)
    : QMainWindow(parent)
{
    m_net = new QNetworkAccessManager(this);
    gameNetManager = new QNetworkAccessManager(this);

    setupUi();
    fetchManifests();
}
平台协议解析

LauncherProtocolHandler::parse

解析 p2plauncher:// 链接,提取房间、用户、服务地址和配置导入参数,并识别链接类型。

launcherprotocolhandler.cpp · L7–L79
原型LauncherProtocolHandler::parse(const QString& url)

调用时机

主客户端或操作系统拉起 Launcher 后调用。

返回说明

返回 ParsedLink;无法识别时类型保持 Unknown。

参数

参数说明
url待解析的平台协议 URL

执行流程

  1. 校验 URL scheme
  2. 提取 query 参数
  3. 识别 game/custom_game 路径
  4. 补齐兼容字段
  5. 返回结构化链接

工程说明

所有深链接参数在进入具体业务前先转为结构化对象。

关联接口

查看完整实现
launcherprotocolhandler.cpp
LauncherProtocolHandler::parse(const QString& url)
{
    ParsedLink link;
    link.originalUrl = url;

    QUrl qurl(url);

    if (!qurl.isValid() || qurl.scheme() != "p2plauncher") {
        return link;
    }

    QString host = qurl.host();
    QString path = qurl.path();

    QUrlQuery query(qurl);

    link.gameId = query.queryItemValue("game_id");
    link.gameName = query.queryItemValue("game_name");
    link.roomId = query.queryItemValue("room_id");
    link.groupId = query.queryItemValue("group_id");
    link.userId = query.queryItemValue("user_id");
    link.token = query.queryItemValue("token");
    link.serverIp = query.queryItemValue("server");
    link.host = query.queryItemValue("host");
    link.port = query.queryItemValue("port").toInt();
    link.containerPort = query.queryItemValue("container_port").toInt();
    link.lobbyPort = query.queryItemValue("lobby_port").toInt();
    link.inviteType = query.queryItemValue("invite_type");
    link.hostUserId = query.queryItemValue("host_user_id");
    link.hostDisplayName = query.queryItemValue("host_display_name");
    link.importFile = query.queryItemValue("file");

    if (host == "game" && path == "/join") {
        link.type = LinkType::GameJoin;
        return link;
    }

    if (host == "custom_game" && path == "/import_config") {
        link.type = LinkType::CustomGameImportConfig;
        return link;
    }

    if (host == "custom_game" && path == "/join") {
        link.type = LinkType::CustomGameJoin;

        if (link.gameId.isEmpty()) {
            link.gameId = "custom_game";
        }

        if (link.gameName.isEmpty()) {
            link.gameName = "自定义游戏";
        }

        if (link.inviteType.isEmpty()) {
            link.inviteType = link.groupId.isEmpty() ? "friend" : "group";
        }

        if (link.lobbyPort <= 0 && link.port > 0) {
            link.lobbyPort = link.port + 100;
        }

        return link;
    }

    return link;
}