QT斗地主游戏(通信基层搭建)

一、客户端架构

  1. 主控制器(Main_Controller)
  • 管理多个子界面控制器:登录、用户界面、游戏大厅、游戏界面
  • 使用状态切换模式:根据Socket连接状态动态切换界面(连接界面/游戏界面)
  • 通过slot_开头的槽函数实现界面跳转逻辑(如登录成功跳转用户界面)
  1. 网络通信模块

Socket类

  • 基于QTcpSocket封装TCP通信

  • 实现消息分帧协议(4字节长度头 + JSON数据)

  • 支持JSON数据收发,按标题(title)分发到不同模块(login/user/game)

SocketFactory

  • 单例工厂模式提供各模块专用Socket(Login_Socket/User_Socket等)
  • 实现模块间通信解耦
  1. 主窗口(MainWindow)
  • 实现无边框窗口和拖动功能
  • 加载QSS样式表美化界面
  • 作为容器承载Main_Controller

二、服务端架构

  1. 核心控制器(Controller)
  • 协调多个业务模块:
    • User_Server:用户信息管理
    • GameHub_Server:游戏大厅/房间管理
    • Game_Server:游戏逻辑处理
  • 通过信号槽机制实现模块间通信
  1. 网络层(Server + TcpServer)

TcpServer

  • 基础TCP服务器实现

  • 处理消息分帧(4字节长度头)

  • 支持多客户端连接管理

Server

  • 连接管理(socket与用户ID映射)
  • 消息路由:按JSON标题分发到对应业务模块
  • 登录验证处理(Login_Server)
  1. 业务处理模块
  • 采用"标题分发"机制:

    json

    Copy

    {
      "title": "game",
      "body": { /* 游戏操作数据 */ }
    }
    
  • 各Server模块通过信号槽接收/发送JSON数据

三、关键设计亮点

  1. 消息协议设计
  • 自定义应用层协议解决TCP粘包:

    cpp

    Copy

    // 发送时添加长度头
    QDataStream stream(&message, QIODevice::WriteOnly);
    stream << dataSize;  // 4字节长度头
    message.append(data);
    
  1. 模块化架构
  • 客户端通过Controller切换界面状态
  • 服务端通过Controller协调业务模块
  • 工厂模式实现通信接口隔离
  1. 信号槽通信机制
  • 跨线程/跨模块通信解耦

  • 客户端示例:

    cpp

    Copy

    connect(m_socket, &Socket::signal_connected, 
            this, &Main_Controller::slot_socket_connected);
    
  • 服务端示例:

    cpp

    Copy

    connect(m_gameHubServer, &GameHub_Server::signal_sendJSON,
            m_server, &Server::sendJSON);
    

四、典型工作流程

  1. 客户端连接流程
启动 -> MainWindow -> Main_Controller 
-> 连接服务器(127.0.0.1:10523) 
-> 连接成功显示登录界面 -> 登录成功后进入用户界面
  1. 游戏操作流程
客户端发送JSON:
{
  "title": "game",
  "name": "playCard",
  "body": {"card": "A♠"}
}

服务端路由:
TcpServer -> Server -> Game_Server 
-> 处理逻辑 -> 广播游戏状态更新

该代码实现了一个完整的网络游戏基础框架,具备良好的扩展性,后续可在各业务模块(如Game_Server)补充具体游戏逻辑即可实现完整斗地主功能。

关键代码

socet.cpp

#include "socket.h"

#include <QJsonDocument>

Socket::Socket(QObject *parent)
    : QObject{parent}
{
    m_tcpSocket = new QTcpSocket(this);
    connect(m_tcpSocket, &QTcpSocket::connected, this, &Socket::signal_connected);
    connect(m_tcpSocket, &QTcpSocket::readyRead, this, &Socket::readyRead);
    connect(m_tcpSocket, &QTcpSocket::disconnected, this, &Socket::signal_disconnected);
}

void Socket::connectToHost(const QString &address, int port)
{
    m_tcpSocket->connectToHost(address,port);
}

void Socket::sendJSON(const QJsonObject &object)
{
    QByteArray data = QJsonDocument(object).toJson();
    this->write(data);
}

void Socket::write(const QByteArray &data)
{
    quint32 dataSize = data.size();
    QByteArray message;
    QDataStream stream(&message, QIODevice::WriteOnly);
    stream << dataSize;
    message.append(data);
    m_tcpSocket->write(message);
}

void Socket::processData(const QByteArray &data)
{
    QJsonObject object = QJsonDocument::fromJson(data).object();
    QString title = object["title"].toString();
    if(title == "login"){
        emit rcv_loginJSON(object);
    }else if(title == "user"){
        emit rcv_userJSON(object);
    }else if(title == "gameHub"){
        emit rcv_gameHubJSON(object);
    }else if(title == "game"){
        emit rcv_gameJSON(object);
    }
}

void Socket::readyRead()
{
    static QByteArray s_data;
    while(m_tcpSocket->bytesAvailable() > 0){
        QByteArray data = m_tcpSocket->readAll();
        if(s_data.isEmpty() == false){
            data = s_data + data;
            s_data.resize(0);
        }

        while(data.size() >= 4){
            quint32 dataSize;
            QDataStream stream(&data, QIODevice::ReadOnly);
            stream >> dataSize;

            if(data.size() >= dataSize + 4){
                QByteArray packet = data.mid(4, dataSize);
                data = data.mid(dataSize + 4);
                this->processData(packet);
            }else{
                s_data.push_back(data);
                break;
            }
        }
    }
}

socketfactory.cpp

#include "socketfactory.h"

Socket* SocketFactory::socket = nullptr;

void SocketFactory::setSocket(Socket *socket)
{
    SocketFactory::socket = socket;
}

const Login_Socket *SocketFactory::loginSocket()
{
    if(SocketFactory::socket == nullptr)
        return nullptr;
    const static Login_Socket *loginSocket = new Login_Socket(socket);
    return loginSocket;
}

const User_Socket *SocketFactory::userSocket()
{
    if(SocketFactory::socket == nullptr)
        return nullptr;
    const static User_Socket *userSocket = new User_Socket(socket);
    return userSocket;
}

const GameHub_Socket *SocketFactory::gameHubSocket()
{
    if(SocketFactory::socket == nullptr)
        return nullptr;
    const static GameHub_Socket *gameHubSocket = new GameHub_Socket(socket);
    return gameHubSocket;
}

const Game_Socket *SocketFactory::gameSocket()
{
    if(SocketFactory::socket == nullptr)
        return nullptr;
    const static Game_Socket *gameSocket = new Game_Socket(socket);
    return gameSocket;
}

你可能感兴趣的:(QT学习笔记,qt,游戏,java)