Qt5.8《网络版够级游戏》编写日志之三:参数配置及数据库访问功能实现

Qt5.8《网络版够级游戏》编写日志之三:参数配置及数据库访问功能实现

 

    无论是服务器端还是客户端都是有一些固定参数进行配置的,同时由于需要用到数据库,因此还需要在服务器端完成服务器端数据库访问方面的操作,作为公共基础的东西,现在就把它们都实现吧。

1 服务器端参数配置类及数据库访问类实现

1.1 数据库访问类实现

1.1.1 数据库访问类主要方法说明

    数据库访问主要是讲访问数据的一些方法集中起来整合成一个类,供服务器访问数据时使用,这里采用的是SqlLite数据库。在GoGeServer项目中添加C++类,选择该类继承自QObject。整个服务器需要进行数据库存储的数据,目前只想到一个就是用户信息表的建立,用户信息表(姓名<Name>、密码<Password>、头像索引<headIcon>、积分<score>、在线状态<status>),其中以Name作为主键。围绕用户信息表,在SDataBase中实现了以下几个功能:

1)    voidresetDataBase();数据库重置,即完成数据库所有表以及数据的删除,同时再对数据库进行建表以及初始数据的插入工作,并建立与数据库的连接;

2)    voidloadDataBase();数据库加载,准确说是数据库连接函数,即建立一个够级用的数据库连接。

3)    voidcreateDataBase(bool flag);创建数据库,根据flag的状态确定是调用resetDataBase()还是loadDataBase()来创建数据库连接。

4)    intloginServer(QString Name,QString Password);登陆服务器查询,依据给定的Name和Password查询该用户是否存在,并返回响应的值,表示查询情况。

5)    intregServer(QString Name,QString Password,qint32 HeadIcon);注册用户,根据提交的Name、Password、HeadIcon,来进行用户信息注册。

6)    voidoffLine();用户下线信息,这个函数用于实现所有用户在线状态置离线的操作,主要是在手动关闭服务器时使用。

7)    voidoffLine(QString Name);以Name为关键字,实现置Name用户为下线状态。

8)    最后还定义了一个信号,用于将数据接口访问类方法使用时的一些信息传送给主界面显示。

1.1.2 数据库访问类方法实现代码

1.1.2.1 resetDataBase()

void SDataBase::resetDataBase()

{

//判断DataBase是否打开,打开的话,则首先关闭

   if(OpenFlag)

       Database.close();

//添加“QSQLITE”,如果是其他数据库类型,则改变

Database =QSqlDatabase::addDatabase("QSQLITE");

//设置数据库名称、用户名、密码,因为这是SQLITE就没有设用户名和密码所以这里就置设定了数据库名称,如果是其他数据库还是进行用户名、密码的设置

   Database.setDatabaseName("GoGeServer.db");

    //打开数据

if(!Database.open())

    {

       //打开不成功的话,置OpenFlag为false,同时向主界面发送数据库连接不成功信号

OpenFlag = false;

       emit sendMsg(0,"数据库连接不成功");

       return;

}

//连接成功后,因为是重置数据库,所有先将数据中Player表删除,然后再重新创建Player表,然后再插入三条默认的用户记录,最后想主界面发送数据库重新创建和连接成功信号。

   OpenFlag = true;

   QSqlQuery Query;

   Query.exec(QObject::tr("drop table Player"));

   Query.exec(QObject::tr("create table Player (name vchar primarykey,password vchar,headIcon int,score int,status vchar)"));

   Query.exec(QObject::tr("insert into Player values('Dave','123',1,0,'OffLine')"));

   Query.exec(QObject::tr("insert into Player values('Lucy','123',11,0,'OffLine')"));

   Query.exec(QObject::tr("insert into Player values ('Nancy','123',15,0,'OffLine')"));

   emit sendMsg(0,"重新创建数据库并连接成功");

}

1.1.2.2 loadDataBase()

    功能比较简单就是连接已有的数据库而已,连接成功就向主界面发送成功的信号信息,否则发送不成功的信号信息。

void SDataBase::loadDataBase()

{

   if(OpenFlag)

       Database.close();

   Database = QSqlDatabase::addDatabase("QSQLITE");

   Database.setDatabaseName("GoGeServer.db");

   if(!Database.open())

    {

       OpenFlag = false;

       emit sendMsg(0,"数据库连接不成功!");

    }

   else

    {

       OpenFlag = true;

       emit sendMsg(0,"数据库连接成功!");

    }

}

1.1.2.3 createDataBase(bool flag)

    创建数据库的方法,其根据flag的状态,选择是直接连接数据库,还是重置数据库操作并连接数据库。

void SDataBase::createDataBase(bool flag)

{

   if(flag)

       loadDataBase();

   else

       resetDataBase();

}

1.1.2.4 loginService(QString Name, QStringPassword)

    用户登陆服务器,根据用户输入的姓名和密码,来返回登陆信息,返回 0:失败,无用户或者密码错误,返回 1**:失败,该用户已上线,返回 2**:成功登陆,**表示该用户的头像索引,这里取了个巧,把用户的头像索引包含在了返回值中。在该方法中,对需要对已经登陆进行判断。

int SDataBase::loginServer(QString Name,QString Password)

{

   if(!OpenFlag)

       return 0;

QSqlQuerysql_query(Database);

//设置查询条件,这里查询用户登陆状态和头像索引

   QString select_sql = "select status,headIcon from Player where name= :name and password = :password";

sql_query.prepare(select_sql);

//将用户的姓名、密码输入值传入

   sql_query.bindValue(":name",Name);

sql_query.bindValue(":password",Password);

//查询

   if(!sql_query.exec())

{

         //如果查询失败,显示失败原因

       qDebug()<<__FUNCTION__<<sql_query.lastError();

       return 0;

    }

   else

{

         //查询成功,也就是用户名和密码对了

       if(sql_query.first())

       {

           QString loginStatus = sql_query.value(0).toString();

           qint32 HeadIcon = sql_query.value(1).toInt();

                          //判断用户是不是不在线

           if(loginStatus == "OffLine")

           {

                               //向服务器主界面发送登陆成功信息,该信息将显示在主界面的服务器信息QtextEdit

                emit sendMsg(0,Name+"登陆成功!");

                                   //同时将该用户的登陆状态置为已登陆状态

                QString update_sql ="update Player set status = 'Online' where name = :name";

                sql_query.prepare(update_sql);

               sql_query.bindValue(":name",Name);

                sql_query.exec();

                return 200+HeadIcon;

           }

           else

           {

                                   //如果用户的状态是在线状态,则想服务器发送重复登陆的信息

                emit sendMsg(0,Name+":重复登陆被拒绝");

                return 100+HeadIcon;

           }

       }

       else

       {

                          //如果查询,没有查到该用户或者密码不对,则向服务器主界面发送不正确信息

           emit sendMsg(0,Name+":用户名或密码不正确!");

           return 0;

       }

    }

   return 0;

}

1.1.2.5 regServer(QString Name, QStringPassword, qint32 HeadIcon)

    用户注册方法,根据用户提供的用户名、密码、头像索引信息进行用户注册操作,注册时要注意该用户名是否已被注册。

int SDataBase::regServer(QString Name,QString Password, qint32 HeadIcon)

{

   if(!OpenFlag)

       return 0;

   //首先查找是否已经有同样的用户名存在

   QSqlQuery sql_query(Database);

   QString select_sql = "select * from Player where name =:name";

   sql_query.prepare(select_sql);

   sql_query.bindValue(":name",Name);

    if(!sql_query.exec())

    {

       qDebug()<<__FUNCTION__<<sql_query.lastError();

       return 0;

    }

   else

    {

       if(sql_query.isValid())

       {

                          //如果找到有同名的用户名存在,则返回有重名信息

           return 1;

       }

       else

       {

                          //没有找到重名的用户名,则开始新用户信息插入工作

           sql_query.clear();

           QString update_sql = "insert into Playervalues(:name,:password,:headIcon,:score,:status)";

           sql_query.prepare(update_sql);

           sql_query.bindValue(":name",Name);

           sql_query.bindValue(":password",Password);

           sql_query.bindValue(":headIcon",HeadIcon);

           sql_query.bindValue(":score",0);

           sql_query.bindValue(":status","OffLine");

           sql_query.exec();

                          //向服务器主界面发送新增用户信息

            emit sendMsg(0,"新增用户:"+Name);

           return 2;

       }

    }

   return 0;

}

1.1.2.6 offLine ()

    将所有用户置为下线状态,这个没什么好说的。

void SDataBase::offLine()

{

   QSqlQuery sql_query(Database);

   QString update_sql = "update Player set status = :status";

   sql_query.prepare(update_sql);

   sql_query.bindValue(":status","OffLine");

   sql_query.exec();

}

1.1.2.7 offLine (QString Name)

    将Name指定的用户置为下线状态,这个也没什么好说的。

void SDataBase::offLine(QString Name)

{

   QSqlQuery sql_query(Database);

   QString update_sql = "update Player set status = 'OffLine' wherename = :name";

   sql_query.prepare(update_sql);

   sql_query.bindValue(":name",Name);

   sql_query.exec();

}

1.2 服务器端配置文件类实现

    该类主要用户记录存放一些服务器运行所需的基本信息,使用QSetting类实现ini配置文件的创建和读取,这些基本信息因为用的地方较多,因此将实例化一个全局的对象,供服务器端的各个类使用。这里也将SDataBase类作为一个成员放在该类中,因为SDataBase也需要在多出使用。服务器端配置文件类我取名叫SconfigSet。

1.2.1 主要成员

    由于想到的统一使用的一些配置信息还不多,因此实现的功能比较有限,主要有这么几个成员,这些都通过ini配置文件进行统一配置。

    quint32 MaxPlayer;//服务器最大可登陆用户数

    quint32 MaxRoom;//服务器最大可创建房间数

    quint32 ServerPort;//服务器TCP端口

    SDataBase ServerDataBase;//数据库访问类

    QString ServerIP;//服务器IP地址

1.2.2 主要方法

    方法不太多,就是三个,一个配置文件创建及初始化方法,一个是配置文件读取,一个是统一加载的方法。

1.2.2.1 loadConfig()

    配置文件加载方法,在该方法内,判断是否存在配置文件,如果不存在配置文件,则调用resetConfig()方法进行配置文件的创建,并用默认值进行初始化;如果存在,则将配置文件中的信息读取到响应的成员变量中。

void SConfigSet::loadConfig()

{

   qint32 CreateOrNot = 0;

   QSettings *settings;

   settings = newQSettings(QDir::currentPath()+"/serverConfig.ini",QSettings::IniFormat);

   //查看是不是第一次运行程序,通过CreateOrNot来判断

   settings->beginGroup("General");

       CreateOrNot = settings->value("CreateOrNot").toInt();

   settings->endGroup();

   delete settings;

settings = NULL;

//判断ini文件是否存在,是通过读取配置文件中CreateOrNot键值,读到且等于5201314,则认为服务器文件存在,如果不是则认为文件不存在需要重新创建

   if(CreateOrNot == 5201314)

    {

       //不是首次运行程序,直接对数据库进行加载

       ServerDataBase.createDataBase(true);

       //读取配置文件

       readConfig();

       emit sendMsg(0,"配置文件读取成功!");

    }

   else

    {

       //首次运行程序,对数据库进行初始化

       ServerDataBase.createDataBase(false);

       //创建配置文件,并初始化配置参数

       resetConfig();

       emit sendMsg(0,"首次运行服务器,创建配置文件成功!");

    }

}

1.2.2.2 resetConfig ()

    重新创建配置文件,并用默认值对成员变量进行初始化工作。

void SConfigSet::resetConfig()

{

QSettings*settings;

//打开配置文件,配置文件默认为放在程序运行目录下

settings = newQSettings(QDir::currentPath()+"/serverConfig.ini",QSettings::IniFormat);

//读取响应的配置文件信息,首先进入“General”节点,然后读取该节点下的数据,目前仅创建了这个节点。配置文件生成后的情况如下:

//  [%General]

//  CreateOrNot=5201314

//  MaxPlayer=24

//  MaxRoom=4

//  ServerIP=127.0.0.1

//  ServerPort=29300

 

   settings->beginGroup("General");

       MaxPlayer = 24;

       MaxRoom = 4;

       ServerPort = 29300;

       ServerIP = "127.0.0.1";

       //设置响应键值的数据

       settings->setValue("CreateOrNot",5201314);

       settings->setValue("MaxPlayer",MaxPlayer);

       settings->setValue("MaxRoom",MaxRoom);

       settings->setValue("ServerPort",ServerPort);

       settings->setValue("ServerIP",ServerIP);

   settings->endGroup();

   delete settings;

   settings = NULL;

}

1.2.2.3 readConfig ()

    读取ini配置文件配置信息。

void SConfigSet::readConfig()

{

   QSettings *settings;

   settings = newQSettings(QDir::currentPath()+"/serverConfig.ini",QSettings::IniFormat);

   settings->beginGroup("General");

       ServerIP = settings->value("ServerIP").toString();

       MaxPlayer = settings->value("MaxPlayer").toUInt();

       MaxRoom = settings->value("MaxRoom").toUInt();

       ServerPort = settings->value("ServerPort").toUInt();

   settings->endGroup();

   delete settings;

   settings = NULL;

}

    至此,服务器的参数配置类和数据库访问类编码已基本实现。个人觉得虽然我把一些常用的东西进行了统一,但是还是有很多优化的地方,后续边写编完善吧。

2 客户端参数配置类功能实现

    客户端参数配置类的实现与服务器端的实现基本一致,只是配置参数不一致而已,下面将成员和主要方法直接列出代码。客户端参数配置类我取名叫SConfigSet。

2.1 主要成员

    quint32 ServerPort;//服务器端口

    QString ServerIP;//服务器IP

    QString LastPlayer;//最近登陆者登陆名

2.2 主要方法

2.2.1 loadConfig()

void SConfigSet::loadConfig()

{

   qint32 CreateOrNot = 0;

   QSettings *settings;

   settings = newQSettings(QDir::currentPath()+"/serverConfig.ini",QSettings::IniFormat);

   //查看是不是第一次运行程序,通过CreateOrNot来判断

   settings->beginGroup("General");

       CreateOrNot = settings->value("CreateOrNot").toInt();

   settings->endGroup();

   delete settings;

   settings = NULL;

 

   if(CreateOrNot == 5201314)

    {

       //读取配置文件

       readConfig();

 

    }

   else

    {

       //创建配置文件,并初始化配置参数

       resetConfig();

    }

}

2.2.2 resetConfig()

void SConfigSet::resetConfig()

{

   QSettings *settings;

   settings = newQSettings(QDir::currentPath()+"/serverConfig.ini",QSettings::IniFormat);

   settings->beginGroup("General");

       ServerPort = 29300;

       ServerIP = "127.0.0.1";

       LastPlayer = "Dave";

       settings->setValue("CreateOrNot",5201314);

       settings->setValue("ServerPort",ServerPort);

       settings->setValue("ServerIP",ServerIP);

       settings->setValue("LastPlayer",LastPlayer);

   settings->endGroup();

   delete settings;

   settings = NULL;

}

2.2.3 readConfig()

void SConfigSet::readConfig()

{

   QSettings *settings;

   settings = newQSettings(QDir::currentPath()+"/serverConfig.ini",QSettings::IniFormat);

   settings->beginGroup("General");

       ServerIP = settings->value("ServerIP").toString();

       LastPlayer = settings->value("LastPlayer").toString();

       ServerPort = settings->value("ServerPort").toUInt();

   settings->endGroup();

   delete settings;

   settings = NULL;

}

3 小结

    至此,服务器和客户端的参数配置类以及数据库访问类的功能基本实现,为了实现这些基本信息的全局调用,我在客户端和服务器端里又新建了一个Global类,这个类中放了一些全局使用的变量以及一些结构的定义,这个随着编写的深入,Global中的内容相对来说会慢慢丰富。目前,在Global类中就是定义了SconfigSet的实例,供全局使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值