学习C++和QT刚刚两个月出头,所以刚听到要做一个类似飞秋,并且可以推送SVN消息的客户端有些担心。但是前辈给了很多帮助,在设计的思路,用什么方法完成功能,到具体的协议解析时的类型转换,都给了很多帮助,所以暂时把登陆端和SVN消息的解析做了出来,下面就说下这部分的收获吧。
PS:可能有些地方我说的有问题,希望了解的朋友可以提出来。
1.做到登陆和注册消息的时候,因为要向服务器发消息,而qt通过套接字(QTcpSocket)中转,需要将消息发送到套接字。后面发送文本消息的时候也需要这样做,所以抽象了一个类专门处理向套接字发消息和从服务器收消息。这样分层结构使得修改代码更简洁,代码重用性也更高。
2.在使用信号与槽的时候,最好在声明槽函数的同时就把信号与槽绑定起来,不然在运行程序的时候会发现槽函数没有运行。
3.在写一个函数的定义,其中有很多判断语句的时候,最好一层一层的写,每一个判断语句的括号一定要记得成对使用,我写的时候没有注意到,最后一个判断少了一个括号,报了莫名其妙的错误。首先,这个函数接着的下一个函数报错“该函数不能重复声明”,其次是后面会有一些变量会报错为“未定义标识符”。
4.登陆界面有个注册按钮和groupbox用信号与槽连接。想实现的功能是:最开始打开登陆界面这个groupbox不显示,在点击按钮后,这个groupbox会显示出来。
要实现这个功能,在构造函数的时候用hide() 将其隐藏,再写一个槽函数,用判断语句isHidden() 和show()来实现。
5.在解析协议的时候,我们规定了一个结构体类型的协议头
enum ReceiverType
{
TO_SOMEONE = 1,
BROADCAST,
};
enum ContentType
{
REGISTER = 1,
ACK_RESULT,
LOGIN,
TEXT,
SVN_LOG,
};
typedef struct tagMessageHeader
{
unsigned int messageLen;
unsigned char sender [64];
ReceiverType receiverType;
unsigned char receiver [64];
ContentType contentType;
} MessageHeader;
或不同情况下在其后的内存空间存放unsigned char[64]或unsigned char *类型的内容。
这里有两点:
一是根据我们的要求,unsigned char *和unsigned char[64]在这里表示着这个变量所占的内存空间,而前者代表不定空间大小,后者固定占64字节的空间。这个与正常的语法不同,遇到这种情况时要根据文档规定的协议要求理解其含义。
二是为了解析协议,需要将每段不同类型的变量分别解析,而整个协议是存放在一个连续的内存空间中。所以要用一个指针来控制具体解析协议的哪一部分。这里需要注意的是要计算每一部分的长度,然后利用长度控制指针的偏移量使其指向下一部分。
6.发送和解析协议的时候我用到了一些类型转换的函数,这里简单介绍一下
data():将QByteArray转换成char*
toLocal8Bit()将QString转化成QByteArray
还有就是需要一些强制类型转换来使得函数的参数匹配。
还有一些学习到的东西可能没有完全列出来,我会在之后继续更新。