Qt小项目:Lanqq开发体会



    大家都知道Qt是一款很强大的面相对象的程序设计开发工具,包含图形界面,支持WPIOS以及Android。经过学习了一段时间以后,用Qt设计客户端,用LINUX设计服务端,实现了这个小项目。

    在这次项目中,实现了以下内容:

【服务端】

1、新用户注册,老用户验证登录,管理员可以对用户实行管理,管理功能有:删除用户并永远不能再注册、对用户进行禁言。

2、点对点私聊、群聊。

3、聊天内容保存和记录。

4、关键词过滤。

5、离线消息。

6、守护进程

【客户端】

1注册、登录、改密

2、私聊群聊。

3、添加组,添加好友。

4、接收离线消息。

5、删除、禁言提示。


**********************************************************************************************************

【项目开始准备】

    本环节是至关重要的,特别是一个团队共同实现一个项目的时候,做好项目的规划能让团队产生1+1>2的效果。

在这个项目中会产生大量的数据传递(同时也是醉主要的一部分),因此必须要准备好通用的数据传递和数据解析时采用的枚举,以保证数据交流的过程中产生不必要的BUG

    一部分枚举定义如下:

**********************************************************************************************************

//type

enum{REGISTER, FORGET,LOGIN,CHANGE,TXT,FILES,ADDFRI,ADDGRP,EXIT,UPDATE,FORBID,ALLOW,REJECT,DELETE,BROADCAST,KEY};

**********************************************************************************************************

    上述的枚举是项目中最重要的枚举,它代表了每个数据传输的目的。其他枚举就不一一列举了,但在定义枚举的时候要注意不要让枚举所代表的值重复,容易出错。

    除了枚举之外还要定义好数据传递时的协议,我们在项目中使用的协议模式是:Type+messagelen+message。

    例如添加好友时我们传递的信息是:ADDFIR+usernamelen+uesrname+friendnamelen+friendname

    要注意因为是QtLINUX之间传输数据,所以我们采用char类型传输,因此在传递“ADDFIR”这个int型枚举时,我们要注意转换。

    除了协议我们还要搭好服务器和客户端的结构,这在接下来会介绍。

    数据库的建立:

****************************************************************************************************************

CREATE TABLE usrinfo(usrno CHAR PRIMARY KEY,usrname VARCHAR(20) NOT NULL,passwd VARCHAR(20) NOT NULL,reject CHAR,speak CHAR,online CHAR,sockfd CHAR,question CHAR,answer VARCHAR(20),friends VARCHAR(50),crowd VARCHAR(50),ismanager CHAR);

CREATE TABLE grpinfo(grpno CHAR PRIMARY KEY,grpname VARCHAR(20) NOT NULL,usrnum VARCHAR(50) NOT NULL);

****************************************************************************************************************


【服务端实现思路】

    服务端在最初的设计上没有把界面考虑在内,因为我们只需要服务器做好数据的解析、转发以及记录的功能就好,不需要在界面上操作,所以选择了再LINUX系统上开发。并且在服务端逻辑处理上没有那么复杂,所以主要根据所需要的功能来进行文件的划分,再进行适当的调用即可:

add.c           //主要处理添加好友和添加组功能  

communicate.c   //处理聊天

login.c        //登陆

main.c

register.c        //注册和密码找回

sqlite.c          //数据库操作

sqlitetest.c       //数据存储 


    其实数据处理的部分还是简单的,这里的难点主要是在数据库方面,如果涉及到数据库方面的程序能好好琢磨,会使你的服务端健壮不少,可惜这方面是我的弱项。

当服务器解析出收到的信息以后,服务器需要进行相应的操作,以添加好友为例,当服务器收到添加好友的信息时,服务器需要先检测数据库列表中是否存在你要添加的friendname,如果存在,需要调用两个id数据库里的friend”列,在该列中添加相应的信息。程序部分代码如下:

 if(sqlite.result==0){

    retmsg=FRI_ERRUSR+'0';

    wtlen=write(clifd,&retmsg,1);

 }

 else{

 sqlite.tag=SQL_GETLIST;

sprintf(sql,"SELECT friends FROM usrinfo WHERE usrname='%s'",myname);

   judgeSQL(&sqlite);

    sqlite.tag=SQL_GETNO;

    sprintf(sql,"SELECT usrno FROM usrinfo WHERE usrname='%s'",friname);

    judgeSQL(&sqlite);

    sqlite.list[strlen(sqlite.list)]=sqlite.usrno;

    sprintf(sql,"UPDATE usrinfo SET friends='%s' WHERE usrname='%s'",sqlite.list,myname);

    execSQL();

    retmsg=FRI_OK+'0';

wtlen=write(clifd,&retmsg,1);

}

void execSQL(){

        char *errmsg;

        if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK){

                sqlite3_close(db);

                printf("%s\n",errmsg);

                sqlite3_free(errmsg);

                return ;

        }

}

    我们再看注册用户的处理(略过判断ID重复之类的检测代码):

 else if(sqlite.result==0){

                sqlite.tag=SQL_SUM;

                sprintf(sql,"SELECT reject FROM usrinfo");

                judgeSQL(&sqlite);

                member.usrno=(++sqlite.sum)+'0';

                sprintf(sql,"INSERT INTO usrinfo VALUES('%c','%s','%s','%c','%c',\

'%c','%s','%c','%s','%s','%s','%c')",member.usrno,member.usrname,member.passwd,\

member.reject,member.speak,member.online,member.sockfd,member.question,member.answer,\

member.friends,member.crowd,member.ismanager);

printf("sql:%s\n",sql);

                execSQL();

                retmsg=REG_OK+'0';

                wtlen=write(clifd,&retmsg,1);

        }


    从上述两段代码上可以看出大部分的代码处理都涉及到数据库。所以我们大可以这样认为,服务端的主要任务就是数据处理和数据库的运行和维护。

    还有一点要提的是我们将每个用户的聊天记录全部保存在文件里,文件名就是用户的ID这样可以减轻数据库的压力,同时查询时也方便,下面附部分代码:

        filefd=open(filename,O_RDWR|O_CREAT,0666);

        if(filefd==-1){

                perror("open");

                return ;

        }

        err=lseek(filefd,0,SEEK_END);

        if(err==-1){

                perror("lseek");

                return ;

        }

        retmsg='\n';

        write(filefd,&retmsg,1);

        retmsg='#';

        write(filefd,&retmsg,1);

        if(online){

                retmsg='1';

                write(filefd,&retmsg,1);

        }

        else{

                retmsg='0';

                write(filefd,&retmsg,1);

        }

        write(filefd,timeval,strlen(timeval));

        retmsg='#';

        write(filefd,&retmsg,1);

        write(filefd,&tag,1);

        write(filefd,&retmsg,1);

        write(filefd,myname,strlen(myname));

        write(filefd,&retmsg,1);

        write(filefd,txt,strlen(txt));

        close(filefd);


 

    只要能将数据部分处理好,服务端的逻辑处理并不难。最后附上服务端函数逻辑:







**************************************************************************************************************

【客户端实现思路】

    客户端是用Qt实现的。Qt的使用让整个服务端的设计更具有层次感,因此对逻辑处理有更高的要求。如果结构设计不好就会使整个Qt程序的数据传递变得比较麻烦,同时也会让程序看起来比较拖沓(本人在这个项目实现过程中深有体会)。由于数据处理方面在服务端部分已经做过阐述,因此这部分主要介绍客户端的结构。

    这里提供两种设计思路:

(1)主要用信号传递数据

    这个方法的核心就是在一个文件里集中处理从服务端发送回来的信号,利用枚举的层次性做出相应的判断,再通过信号将数据传送给不同的界面做出相应的相应。这个方法的优点是逻辑处理相对简单,所有界面都处于同一层,整个数据传递的过程集中、清晰。如果上层结构对下层结构用信号进行数据传递会产生很多BUG,这个结构可以很好的规避这一点。

结构图如下:

    由上图可以看出,所有的功能界面处于同一级,每当有一个“pushbutton”被按下时就向“client”界面发送一个请求,所有的信息交互由“client”界面和服务器进行交互,同时在“client”中解析所有从服务器中传递来的信息,再通过相应的函数传输给下面的功能界面。因为有枚举,所以不用担心数据传递的出错。这种方法总体来说结构和思路都很清晰,而且方便添加新的功能,唯一的缺点应该就是客户端内的数据传递比较多。

优先推荐这种设计方法。


(2)在相应的功能界面传递数据

这个方法核心就是在每个功能界面都有一个“connect”用来与服务端进行信息交互。结构图如下:

    从上图可以看出,和第一种方面明显的区别是这里的每个功能窗口并不是同级的,因此并不适合用signal进行信号传递。当用户登录成功后,我们便将第一个界面建立的socket通过函数传给下一个界面,这样整个程序可以共用一个socket。通过在每个界面中用socket和服务器进行数据交互,这样就达到了在相应的功能界面和服务器进行相应的数据交互的目的。这种结构的优点是可以自行选择什么时候和服务器进行连接。如上图,当你打开登录界面的时候并没有和服务器建立连接,只有当你申请登录、注册、找回密码时才进行数据交互。对服务器的负荷相对较小,同时客户端内信息交互较少。当然缺点也是比较明显的,添加功能不如第一种方法方便,逻辑设计较第一种稍难。



   

    接下来附上一段服务端ADDFRIEND的代码:

   QString friendname;

  QString type;

  if(ui->friendnumlineEdit->text().isEmpty()){

      QMessageBox::warning(this,"warning","no friend username");

      return;

  }

  type.setNum(ADDFRI);

  friendname+=type;

  char mynameLength = username.toLatin1().length()+'0';

  friendname+=mynameLength;

  friendname+=username;

  char friendnameLength = ui->friendnumlineEdit->text().toLatin1().length()+'0';

  friendname+=friendnameLength;

  friendname += ui->friendnumlineEdit->text().toLatin1();

  QByteArray cd;

  char *pf;

  cd=friendname.toLatin1();

  pf=cd.data();qDebug()<<pf;

  if(socket->state()==QAbstractSocket::ConnectedState)

      socket->write(pf);

    在本段代码中涉及到数据类型的转化和数据的传递。要注意我们和服务端交互信息采用的是char型。还有一点要注意的就是将ADDFRI转化为QString类型的时候,在本段代码中因为ADDFRI的枚举值小于10所以没有出错,若枚举值大于10,则需要采用type = ADDFRI+'0'

这种方式。




【结语】

    服务器和客户端的设计思路有所不同,侧重点也有所不同,这个项目对知识的掌握还是有很大的帮助的。等以后能力更上一层楼以后,说不定看现在的设计都是缺点,但这是成长的必经之路。用此文纪念我的学习生涯。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
2022年11月4日-2022年11月14日购买当前课程赠送课程学习地址如下:https://edu.csdn.net/course/detail/32434https://edu.csdn.net/course/detail/35658https://edu.csdn.net/course/detail/30223https://edu.csdn.net/course/detail/32408https://edu.csdn.net/course/detail/32429注:因赠送课程不会出现在已订阅课程列表中,以下课程学习地址一定要收藏保存。#课程服务 在线答疑:本课程设有专门的讨论留言区,学习中遇到任何问题,直接给老师留言即可,老师都会及时进行回复。远程协助:如果遇到复杂问题,老师还可进行远程协助,这个一般可不是一两百元的课程就能享受到的。源码分享:为了让大家更好的进行项目实战,老师还将课程中涉及到的所有源码分享给学员,按照视频中的提示进行下载即可。在CSDN分享C++ Qt开发知识已经有6年了,感谢众多博友对我的支持,了解到很多人对Qt的使用还是有些困扰,例如Qt环境搭建,Qt布局的使用,如何使用Qt编写复杂的界面,如何自定义非标控件,Qt如何和Web交互,Qt和后台接口如何交互等;经过这几年的整理,我决定出这套《Qt高级开发视频教程》,带领大家学习Qt高级开发知识,学习如何使用Qt开发企业级别的项目;通过本课程的学习,大家将会达到企业招聘的中高级要求。为了照顾零基础学员,本课程第一章会介绍Qt环境搭建、QtCreator / VS2019的基本使用方法,Qt整体架构、Qt信号机制,Qt内存管理等知识。即使没有Qt开发的学习经验,也能跟着课程顺利学习。课程核心知识点地图如下: 课程每章核心知识点介绍如下: 第一章:介绍Qt环境搭建、QtCreator / VS2019的基本使用方法,Qt整体架构、Qt信号机制,Qt内存管理等知识。第二章:了解到很多学员对于Qt界面布局很不熟悉,将会详细介绍Qt设计器布局,以及如何C++代码手写布局,从常见的企业级项目入手,带领大家学会各种布局的实现,例如WPS、腾讯会议、优酷、迅雷等界面的实现;界面布局会了,这是企业项目开发的第一步,还有更重要的无边框窗口,如何设计一个合理的无边框窗口很重要,第三/四章:详细介绍如何实现一个无边框窗口,如何自定义标题栏,如何实现拖拽拉伸;第四章将会介绍如何自定义非标控件,优化Qt界面。第五章:介绍Qt web混合编程,一个商用项目,必然会涉及到web交互,这也是很多Qt开发者的弱项,这一章讲详细介绍C++ Qt web混合开发。第六章:既然是做企业级项目,必然需要和后台交互,http编程也是必要的,将详细介绍http编程,用户注册,登录,后台接口请求等知识;通过第五、六章的学习,将会是你的Qt开发技术更上一层楼。第七章:介绍Qt并发编程,耗时任务处理,进程调用等知识。第八、九章:讲解 Qt 比较重要的知识,图形视图结构,以及MVD模式;通过这两章的学习,大家会对图形视图有更好的了解。第十章:本章是独立章节,主要介绍Qt中一些特殊技巧,项目编译,dpi适配、多语言等知识。第十一章:是我们的企业级项目实战:实现一个视频会议客户端,本项目可以进行多人视频通话,直播,桌面分享等功能,本项目我会从零开始,进行项目搭建,功能调试,bug fixed, 带领大家做一个企业级项目。希望通过本课程的学习,大家的C++ Qt开发技术能有质的飞越,能找到自己心仪的工作。课程中如果讲的不对的地方,请大家指出,我及时修正,我也只是一个普通开发者,也不是所有的技术都会,尽我所能,把我所会的教给大家,让我们一起为Qt的发展,尽一份绵薄之力。 下面是本课程一些项目的截图: 1 可以滑动的设置界面         2 所有图形的绘制       3 视频播放器          4 高仿youku界面         5 视频会议         相信通过本课程的学习,大家有能力实现绝大部分客户端项目,从此用C++ Qt再也不会有难写的界面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值