7.7 KiB
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. 关键组件职责
- GameClient (客户端)
- 负责连接服务器。
- 必须使用多线程:一个线程(主线程)负责捕获用户输入 (cin) 并 send;另一个线程(子线程)负责阻塞 recv 并打印服务器消息 (cout)。
- 负责提供控制台的菜单和界面。
- GameServer (服务器)
- 负责监听端口 (listen) 和接受新连接 (accept)。
- 每接受一个新连接,必须创建一个 ClientHandler 实例,并在一个新线程 (std::thread) 中运行它。
- 必须使用 std::map (STL) 来存储所有 ClientHandler 的指针或引用,以便管理。
- 必须使用 std::mutex (STL) 来保护这个 map,防止多线程冲突。
- ClientHandler (服务器)
- 在独立的线程中运行,代表一个已连接的客户端。
- 负责该客户端的 recv 循环,解析客户端发来的命令 (使用 Protocol.h)。
- 根据命令,调用 GameLobby (聊天/邀请) 或 BattleRoomManager (战斗) 的功能。
- 负责处理该客户端的异常掉线,并通知 GameServer 将自己从 map 中移除。
- GameLobby (服务器)
- 管理所有处于“大厅”状态的玩家。
- 实现 broadcastMessage() (广播聊天),需要加锁 (std::mutex) 遍历 GameServer 的客户端 map 并发送。
- 实现 handleInvite() (处理邀请逻辑)。
- BattleRoom (服务器)
- 负责处理一场 1v1 战斗。
- 持有多态的 ICharacter* 指针。
- 持有模板+链表实现的 HistoryLog<string> 实例,用于记录战报。
- 实现 runTurn() 战斗循环逻辑,调用 ISkill 的 execute 方法。
- Database (服务器)
- 封装 SQLite3 的 C API。
- 提供上层易用的接口:bool registerUser(user, pass)等。
- 必须保证是线程安全的(例如,对所有数据库写操作使用一个全局 std::mutex)。
3. 关键数据流
3.1. 数据流:玩家A 发送大厅聊天
- [Client A]:主线程 cin 捕获输入 "Hello"。
- [Client A]:GameClient 将其打包为 "CHAT|Hello",通过 SocketWrapper::send() 发出。
- [Server]:ClientHandler A (线程A) 的 recv() 循环收到数据。
- [Server]:ClientHandler A 解析出是 CHAT 命令。
- [Server]:ClientHandler A 调用 GameLobby::broadcastMessage("A: Hello")。
- [Server]:GameLobby 加锁访问 GameServer 的客户端 map。
- [Server]:GameLobby 遍历 map,对所有非战斗中的 ClientHandler (如 B, C, D) 调用 send("MSG|A: Hello")。
- [Client B,C,D]:接收线程 (子线程) 的 recv() 收到消息,cout 打印 "A: Hello" 到控制台。
3.2. 数据流:玩家A 攻击 玩家B (战斗中)
- [Server]:BattleRoom (线程C) 判定轮到 A 行动。
- [Server]:BattleRoom 向 ClientHandler A (线程A) 发送 "TURN|YOUR_TURN"。
- [Client A]:接收线程收到 "TURN|YOUR_TURN",cout 打印 "轮到你行动"。
- [Client A]:主线程 cin 捕获输入 "attack B"。
- [Client A]:GameClient 打包为 "BATTLE|USE_SKILL|Fireball|B",send() 发出。
- [Server]:ClientHandler A (线程A) 收到数据,解析后调用 BattleRoom::handleAction("A", "Fireball", "B")。
- [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); (模板+链表调用) - [Server]:BattleRoom (线程C) 将战报 log 广播给 ClientHandler A 和 ClientHandler B。
- [Client A, B]:接收线程收到 log,cout 打印战报。