LibQQt系列之十一《QQt通讯模块介绍和实践》

这篇文章以UDP通信为例进行介绍。UDP比较简单,在windows上用的挺多。
QQt版本v2.1.7.0

QQt通讯模组

QQt通讯模组分为三个部分,通讯接口,通讯协议,通讯报文。
大多数的工作都集中在通讯协议部分,通讯报文是通讯的数据包。

QQtSocketUdpClient

它负责在硬件上通信。客户端服务器都用这个类,服务器bind本地端口一下,其他相同使用方法。太简单了。
需要安装QQtUdpProtocol进行使用。

QQtUdpProtocol

它是重点,用它可以直接发送报文,接收报文。
用户主要实现的就是这个类的子类。
在此以一个检测系统的系统协议进行讲解。

通信有多个Client

在继承下来的类当中,这样处理,和多个客户端通信的时候的客户端连接。
重点在于这个Protocol,只有一个。

CedianUdpProtocol *cedianUdpServer(QObject *parent)
{
    static CedianUdpServer* s0[9] = {NULL};
    static CedianUdpProtocol* p0 = NULL;
    if(!s0[0] && !p0)
    {
        p0 = new CedianUdpProtocol(parent);
        for(int i =0; i < 9; i++)
        {
            int port = cedianUdpPort(i+1);
            pline() << i+1 << port;

            s0[i] = new CedianUdpServer(parent);
            /*通讯端口:绑定本地端口*/
            s0[i]->bind(port);
            /*通讯端口:给测点协议*/
            s0[i]->installProtocol(p0);
        }
    }
    return p0;
}

收到消息

重载dispatcher函数咯,在父类当中介绍了。

bool CedianUdpProtocol::dispatcher(const QNetworkDatagram & dg)
{
    mDG = dg;
    mAddress = dg.senderAddress();
    mPort = dg.senderPort();
    mLocalPort = dg.destinationPort();
    QByteArray data = dg.data();
    mMsg.parser(data);
    emit msgIncoming();
}

获取收到的消息

你看到发的信号吗?在哪里进行收取。需要什么信息,就把什么信息保存在局部变量里,通过函数公开出来。
那个mMsg是什么?它是通讯模组的第三个重点。数据报。

QQtMessage

这个类真的是老生常谈,到哪里都是它。
它里面就两个函数,
packer,把要发送的打包到QByteArray里。
parser,把收到的解压到局部变量中。程序中总是用这些局部变量。
其实还有一个打印函数,可以打印数据报的报文。


QDebug operator<<(QDebug dbg, const CedianUdpMessage &c)

{

    //    dbg.nospace() << "{" << hex << c.head() << "|" <<

    //                     hex << c.size() << "=" << dec << c.size() << "|" <<

    //                     hex << c.cmd() << "|" <<

    //                     hex << c.uid() << "|" <<

    //                     c.data().data() << "@" << dec << c.data().size() << "|" <<

    //                     hex << c.sum() << "|" <<

    //                     hex << c.tail() << "}";

    dbg.nospace() << "{" << hex << "}";

    return dbg.space();

}


这个类,是用户最感兴趣的类,因为用户度数据压缩、解压缩都在这里。其实就是分散的变量和QByteArray之间的转换。格式转换。
这个类的两个函数里都有丰富的QByteArray的操作符重载函数调用。很是带劲。


void CedianUdpMessage::parser(const QByteArray & data)

{

    QByteArray l = data;

    quint8 DataLen = 0, temp = 0, Month = 0, Day = 0, Hour = 0, Minute = 0, Second =0;

    quint16 Year = 0;

    //跳过包头 0-5

    for (int i=0; i<6 ;i++)

    {

        l >> temp;

        DataLen++;

    }

    //跳过空格 6

    l >> temp;

    DataLen++;

    //日 7-8

    l >> temp;

    mqbaDateTime << temp;

    Day = 10 * (temp - 0x30);

    l >> temp;

    mqbaDateTime << temp;

    Day = Day + (temp - 0x30);

    DataLen = DataLen + 2;

    //月 9-10

    l >> temp;

    mqbaDateTime << temp;

    Month = 10 * (temp - 0x30);

    l >> temp;

    mqbaDateTime << temp;

    Month = Month + (temp - 0x30);

    DataLen = DataLen + 2;

    //年 11-12

    l >> temp;

    mqbaDateTime << temp;

    Year = 10 * (temp - 0x30) + 2000;

    l >> temp;

    mqbaDateTime << temp;

    Year = Year + (temp - 0x30);

    DataLen = DataLen + 2;

    //跳过空格 13

    l >> temp;

    DataLen++;

    //时 14-15

    l >> temp;

    mqbaDateTime << temp;

    Hour = 10 * (temp - 0x30);

    l >> temp;

    mqbaDateTime << temp;

    Hour = Hour + (temp - 0x30);

    DataLen = DataLen + 2;

    //分 16-17

    l >> temp;

    mqbaDateTime << temp;

    Minute = 10 * (temp - 0x30);

    l >> temp;

    mqbaDateTime << temp;

    Minute = Minute + (temp - 0x30);

    DataLen = DataLen + 2;

    //秒 18-19

    l >> temp;

    mqbaDateTime << temp;

    Second = 10 * (temp - 0x30);

    l >> temp;

    mqbaDateTime << temp;

    Second = Second + (temp - 0x30);

    DataLen = DataLen + 2;

    //拼接并赋值给成员变量 年月日时分秒

    mDateTime = QString("%1-%2-%3 %4:%5:%6").arg(Year).arg(Month).arg(Day).arg(Hour).arg(Minute).arg(Second);

    //跳过空格 20

    l >> temp;

    DataLen++;

    //秒内标号 21-22

    l >> temp;

    mqbaBuffer << temp;

    mBuffer = 10 * (temp - 0x30);

    l >> temp;

    mqbaBuffer << temp;

    mBuffer = mBuffer + (temp - 0x30);

    DataLen = DataLen + 2;

    //跳过空格 23

    l >> temp;

    DataLen++;

    //频率mFA 24-30

    l >> temp;

    mqbaFA << temp;

    mFA = (temp - 0x30) * 100000;

    l >> temp;

    mqbaFA << temp;

    mFA = mFA + (temp - 0x30) * 10000;

    l >> temp; //小数点

    mqbaFA << temp;

    l >> temp;

    mqbaFA << temp;

    mFA = mFA + (temp - 0x30) * 1000;

    l >> temp;

    mqbaFA << temp;

    mFA = mFA + (temp - 0x30) * 100;

    l >> temp;

    mqbaFA << temp;

    mFA = mFA + (temp - 0x30) * 10;

    l >> temp;

    mqbaFA << temp;

    mFA = mFA + (temp - 0x30);

    mFA = mFA / 10000;

    DataLen = DataLen + 7;

    //跳过空格 31

    l >> temp;

    DataLen++;

    //频率弃用 32-38

    for (int i=0; i<7 ;i++)

    {

        l >> temp;

        DataLen++;

    }

    //跳过空格 39

    l >> temp;

    DataLen++;



    //电压幅值mVAA 40-45

    l >> temp;

    mqbaVAA << temp;

    mVAA = (temp - 0x30) * 10000;

    l >> temp;

    mqbaVAA << temp;

    mVAA = mVAA + (temp - 0x30) * 1000;

    l >> temp;

    mqbaVAA << temp;

    mVAA = mVAA + (temp - 0x30) * 100;

    l >> temp;  //小数点

    mqbaVAA << temp;

    l >> temp;

    mqbaVAA << temp;

    mVAA = mVAA + (temp - 0x30) * 10;

    l >> temp;

    mqbaVAA << temp;

    mVAA = mVAA + (temp - 0x30);

    mVAA = mVAA / 100;

    DataLen = DataLen + 6;



    //跳过空格 46

    l >> temp;

    DataLen++;

    //电压相位mVPA 47-51

    l >> temp;

    mqbaVPA << temp;

    mVPA = (temp - 0x30) * 1000;

    l >> temp;  //小数点

    mqbaVPA << temp;

    l >> temp;

    mqbaVPA << temp;

    mVPA = mVPA + (temp - 0x30) * 100;

    l >> temp;

    mqbaVPA << temp;

    mVPA = mVPA + (temp - 0x30) * 10;

    l >> temp;

    mqbaVPA << temp;

    mVPA = mVPA + (temp - 0x30);

    mVPA = mVPA / 1000;

    mVPA = mVPA * 57.296;

    DataLen = DataLen + 5;

    //跳过包尾 52-54

    for (int i=0; i<3 ;i++)

    {

        l >> temp;

        DataLen++;

    }

}


void CedianUdpMessage::packer(QByteArray & l) const

{

}

是不是觉得很难?数据报很长,当然这个运算符操作就多了。可是这些操作,你只需要写这一遍代码,在Protocol当中用函数就可以了。那边可是有很丰富的通讯命令。
如果每个命令都写一遍这种操作,甚至更复杂的操作,那岂不是害死自己?

通讯模组就讲到这,有需要,请查阅qqtnetworkexample例子工程。

有人说,公开这些协议是不是不规范?跟你说吧,那是噱头。你拿到这个协议一点用处都没有。
在新开发的工程当中,每个通讯位置你都必须写一个通讯协议,才能完成你的工程。
不过我默认不会公开这些协议的。这个只是个参考学习工程。
鼓励开发common协议。

你可能感兴趣的:(QQt)