• 文本协议篇2- 从字节流装配文本协议对象


    1.如何将接收缓冲区中的数据装配成协议对象

    • 上一节中提到的unserialize函数用于将一个符合协议规则的字符串装配成为一个协议对象。可是在实际工程开发过程中可能会是一个问题:接收缓冲区中的数据一定是满足协议的定义规则吗? 
      答案是:不一定

    2.如果接收缓冲区中的数据不满足协议规则能否将其装配成一个协议对象

    • 接收缓冲区中的数据足够
      • 如果数据量足够是否能够装配成不只是一个对象?
      • 剩下的数据如何处理(属于下一个协议对象)?
    • 数据量不足
      • 是否达到协议最小长度(8字节)?
      • 如何处理数据量超过最小长度但不足以产生一个新对象

    3.解决方案

    • 定义一个类用于接收字节流数据,并装配协议对象
    • 类中提供容器(队列)用于暂存字节流数据
    • 当容器中至少存在8个字节时开始装配
      1. 首先装配协议中的类型(type)和数据区长度(length)
      2. 根据数据区长度从容器中取数据装配协议数据(data)
      3. 当协议数据装配完成后,创建协议对象并返回,否则,返回NULL

    4.代码

    目的:实现将字符串装配成一个完整的协议对象。 
    main函数测试目标 将完整的协议字符串分两次写到内存中,通过 
    TxtMsgAssembler类完成对协议的装配 
    代码: 
    txtmsgassembler.h

     1 #ifndef TXTMSGASSEMBLER_H
     2 #define TXTMSGASSEMBLER_H
     3 
     4 #include <QObject>
     5 #include <QQueue>
     6 #include <QSharedPointer>
     7 #include "TextMessage.h"
     8 
     9 class TxtMsgAssembler : public QObject
    10 {
    11     Q_OBJECT
    12     QQueue<char> m_queue;//存储字节流
    13     QString m_type;
    14     int m_length;
    15     QString m_data;
    16 
    17 
    18 public:
    19     explicit TxtMsgAssembler(QObject *parent = nullptr);
    20 
    21     QSharedPointer<TextMessage> assemble();//从内部容器中获取字节数据,尝试装配字节对象
    22     QSharedPointer<TextMessage> assemble(const char* data,int length);
    23     void prepare(const char* data, int len);//将数据转存到内部容器,用于后续协议对象装配
    24     void reset();
    25     void clear();
    26     bool makeTypeAndLength();
    27 
    28     TextMessage*  makeMessage();
    29     QString fetch(int n);
    30 signals:
    31 
    32 public slots:
    33 };
    34 
    35 #endif // TXTMSGASSEMBLER_H

    txtmsgassembler.cpp

      1 #include "txtmsgassembler.h"
      2 
      3 TxtMsgAssembler::TxtMsgAssembler(QObject *parent) : QObject(parent)
      4 {
      5 
      6 }
      7 
      8 QSharedPointer<TextMessage> TxtMsgAssembler::assemble(const char *data, int length)
      9 {
     10     prepare(data,length);
     11     return assemble();
     12 }
     13 
     14 QSharedPointer<TextMessage> TxtMsgAssembler::assemble()
     15 {
     16     TextMessage* ret=NULL;
     17 
     18     bool tryMakeMsg=false;
     19     if(m_type=="")
     20     {
     21        tryMakeMsg=makeTypeAndLength();
     22     }
     23     else
     24     {
     25         tryMakeMsg=true;
     26     }
     27 
     28    if(tryMakeMsg)
     29    {
     30        ret = makeMessage();
     31     }
     32 
     33    if(ret!=NULL)
     34     {
     35         clear();
     36     }
     37 
     38     return QSharedPointer<TextMessage>(ret);
     39 }
     40 
     41 void TxtMsgAssembler::prepare(const char* data, int len)
     42 {
     43     if(data!=NULL)
     44     {
     45         for(int i=0;i<len;i++)
     46         {
     47             m_queue.enqueue(data[i]);
     48         }
     49     }
     50 }
     51 
     52 void TxtMsgAssembler::reset()
     53 {
     54     clear();
     55     m_queue.clear();
     56 }
     57 
     58 void TxtMsgAssembler::clear()
     59 {
     60     m_type="";
     61     m_length=0;
     62     m_data="";
     63 }
     64 
     65 bool TxtMsgAssembler::makeTypeAndLength()
     66 {
     67     bool ret=(m_queue.length()>=8);
     68 
     69     if(ret)
     70     {
     71         m_type=fetch(4);
     72         QString len =fetch(4).trimmed();
     73         m_length=len.toInt(&ret,16);
     74 
     75         if(!ret)
     76        {
     77             clear();
     78         }
     79     }
     80     return ret;
     81 }
     82 
     83 
     84 
     85 
     86 TextMessage* TxtMsgAssembler::makeMessage()
     87 {
     88     TextMessage* ret=NULL;
     89 
     90     if(m_type!="")
     91     {
     92         int needlen=m_length-m_data.length();
     93 
     94         int n=(needlen<=m_queue.length())?needlen:m_queue.length();
     95         m_data+=fetch(n);
     96 
     97         if(m_length==m_data.length())
     98         {
     99             ret=new  TextMessage(m_type,m_data);
    100         }
    101 
    102     }
    103     return ret;
    104 }
    105 
    106 QString TxtMsgAssembler::fetch(int n)
    107 {
    108     QString ret;
    109 
    110     for(int i=0;i<n;++i)
    111     {
    112         ret+=m_queue.dequeue();
    113     }
    114 
    115     return ret;
    116 }

    main.cpp

     1 #include <QCoreApplication>
     2 #include <QDebug>
     3 #include "textmessage.h"
     4 #include "txtmsgassembler.h"
     5 
     6 int main(int argc, char *argv[])
     7 {
     8     QCoreApplication a(argc, argv);
     9 
    10     TextMessage tm("AB","1234567890");
    11     QString message=tm.serialize();
    12     qDebug()<<message;
    13 
    14     QString s1=message.mid(0,5);
    15     QString s2=message.mid(5);
    16 
    17     QSharedPointer<TextMessage> tmt;
    18     TxtMsgAssembler as;
    19 
    20     tmt=as.assemble(s1.toStdString().c_str(),s1.length());
    21     if(tmt!=NULL)
    22     {
    23         qDebug()<<"assembel sucessed.";
    24         qDebug()<<tmt->type();
    25         qDebug()<<tmt->length();
    26         qDebug()<<tmt->data();
    27     }
    28 
    29     tmt=as.assemble(s2.toStdString().c_str(),s2.length());
    30     if(tmt!=NULL)
    31     {
    32         qDebug()<<"assembel sucessed.";
    33         qDebug()<<tmt->type();
    34         qDebug()<<tmt->length();
    35         qDebug()<<tmt->data();
    36     }
    37     return a.exec();
    38 }

    说明:textmessage.h参考上一节同名文件

    效果:

    5.小结

    • 从连续字节流装配协议对象是应用自定义协议的基础
    • 装配类TxtMsgAssembler用于解析自定义协议
    • 装配类的实现的关键是如何处理字节数据不够的情况
    • 自定义协议类和装配类能够有效的解决数据粘粘的问题
  • 相关阅读:
    C语言I博客作业07
    C语言I博客作业06
    C语言I博客作业05
    C语言I博客作业04
    C语言I博客作业03
    C语言第二周作业
    C语言第一周课程作业
    C语言期末总结
    第一次作业
    C语言I博客作业09
  • 原文地址:https://www.cnblogs.com/zhaobinyouth/p/12268661.html
Copyright © 2020-2023  润新知