Files
OnlineRpg/系统架构设计.md
ChuXun e287aadd3c 1
2025-10-26 16:37:22 +08:00

7.7 KiB
Raw Permalink Blame History

1. 系统架构图 (C/S 架构)

+-------------------------------------------------------------------------+
| [ 客户端 A (Console) ] |
| +--------------------+ +--------------------+ |
| | GameClient | | 主线程 (Input) | |
| | (负责网络通信) | | (发送聊天/指令) | |
| +--------------------+ +--------------------+ |
| | SocketWrapper | | 接收线程 (Recv) | |
| | (封装Socket API) | | (打印聊天/战报) | |
| +--------------------+ +--------------------+ |
+-------------^----------------------------------+ |
| (TCP/IP) |
| |
+-------------v----------------------------------+ |
| [ 客户端 B (Console) ] |
| (结构同 A) |
+-------------^----------------------------------+ |
| (TCP/IP) |
| |
+-------------v-----------------------------------------------------------+
| [ 服务器 (GameServer Console) ] |
| |
| +---------------------+ +-----------------------------------------+ |
| | GameServer (主线程) | | [ 线程池 / 并发管理 ] | |
| | (Socket, Bind, Listen)| | | |
| | (Loop: Accept) | | +-----------------+ +-----------------+ | |
| | | | | ClientHandler A | | ClientHandler B | | |
| | (管理所有 Client) | | | (Thread A) | | (Thread B) | | |
| | (std::map<fd, Ptr>)| | +-----------------+ +-----------------+ | |
| +----------^----------+ +---------^---------------+---------^-----+ |
| | | (Lobby/Battle) | |
| | | | |
| +----------v----------+ +---------v---------------+ | |
| | GameLobby (单例) | | BattleRoomManager | | |
| | (std::map<name, Ptr>)| | (管理所有战斗房间) | | |
| | (负责聊天/邀请) | | (std::map<id, Ptr>) | | |
| +---------------------+ +-----------------------+ | |
| | |
| +-------------------------------v-------+ |
| | [ 数据库接口 (Database) ] | |
| | (封装 SQLite API) | |
| | (使用 Mutex 保证线程安全) | |
| +-------------------^-------------------+ |
| | |
+---------------------------------------------------+---------------------+
|
+---v---+
| DB |
| (users.db)|
+-------+

2. 关键组件职责

  1. GameClient (客户端)
    • 负责连接服务器。
    • 必须使用多线程:一个线程(主线程)负责捕获用户输入 (cin) 并 send另一个线程子线程负责阻塞 recv 并打印服务器消息 (cout)。
    • 负责提供控制台的菜单和界面。
  2. GameServer (服务器)
    • 负责监听端口 (listen) 和接受新连接 (accept)。
    • 每接受一个新连接,必须创建一个 ClientHandler 实例,并在一个新线程 (std::thread) 中运行它。
    • 必须使用 std::map (STL) 来存储所有 ClientHandler 的指针或引用,以便管理。
    • 必须使用 std::mutex (STL) 来保护这个 map防止多线程冲突。
  3. ClientHandler (服务器)
    • 在独立的线程中运行,代表一个已连接的客户端。
    • 负责该客户端的 recv 循环,解析客户端发来的命令 (使用 Protocol.h)。
    • 根据命令,调用 GameLobby (聊天/邀请) 或 BattleRoomManager (战斗) 的功能。
    • 负责处理该客户端的异常掉线,并通知 GameServer 将自己从 map 中移除。
  4. GameLobby (服务器)
    • 管理所有处于“大厅”状态的玩家。
    • 实现 broadcastMessage() (广播聊天),需要加锁 (std::mutex) 遍历 GameServer 的客户端 map 并发送。
    • 实现 handleInvite() (处理邀请逻辑)。
  5. BattleRoom (服务器)
    • 负责处理一场 1v1 战斗。
    • 持有多态的 ICharacter* 指针。
    • 持有模板+链表实现的 HistoryLog<string> 实例,用于记录战报。
    • 实现 runTurn() 战斗循环逻辑,调用 ISkill 的 execute 方法。
  6. Database (服务器)
    • 封装 SQLite3 的 C API。
    • 提供上层易用的接口bool registerUser(user, pass)等。
    • 必须保证是线程安全的(例如,对所有数据库写操作使用一个全局 std::mutex

3. 关键数据流

3.1. 数据流玩家A 发送大厅聊天

  1. [Client A]:主线程 cin 捕获输入 "Hello"。
  2. [Client A]GameClient 将其打包为 "CHAT|Hello",通过 SocketWrapper::send() 发出。
  3. [Server]ClientHandler A (线程A) 的 recv() 循环收到数据。
  4. [Server]ClientHandler A 解析出是 CHAT 命令。
  5. [Server]ClientHandler A 调用 GameLobby::broadcastMessage("A: Hello")。
  6. [Server]GameLobby 加锁访问 GameServer 的客户端 map。
  7. [Server]GameLobby 遍历 map对所有非战斗中的 ClientHandler (如 B, C, D) 调用 send("MSG|A: Hello")。
  8. [Client B,C,D]:接收线程 (子线程) 的 recv() 收到消息cout 打印 "A: Hello" 到控制台。

3.2. 数据流玩家A 攻击 玩家B (战斗中)

  1. [Server]BattleRoom (线程C) 判定轮到 A 行动。
  2. [Server]BattleRoom 向 ClientHandler A (线程A) 发送 "TURN|YOUR_TURN"。
  3. [Client A]:接收线程收到 "TURN|YOUR_TURN"cout 打印 "轮到你行动"。
  4. [Client A]:主线程 cin 捕获输入 "attack B"。
  5. [Client A]GameClient 打包为 "BATTLE|USE_SKILL|Fireball|B"send() 发出。
  6. [Server]ClientHandler A (线程A) 收到数据,解析后调用 BattleRoom::handleAction("A", "Fireball", "B")。
  7. [Server]BattleRoom (线程C) 加锁(防止多线程同时修改战斗状态),执行战斗逻辑:
    a. ICharacter* charA = ...;
    b. ISkill* skill = charA->getSkill("Fireball");
    c. skill->execute(charA, charB); (多态调用)
    d. string log = "A 对 B 使用了[火球]...";
    e. m_historyLog.add(log); (模板+链表调用)
  8. [Server]BattleRoom (线程C) 将战报 log 广播给 ClientHandler A 和 ClientHandler B。
  9. [Client A, B]:接收线程收到 logcout 打印战报。