【问题标题】:Parsing buffer data in C++在 C++ 中解析缓冲区数据
【发布时间】:2012-10-18 12:18:51
【问题描述】:

我的 C++ 项目有一个缓冲区,它可以是任意大小并由蓝牙填充。传入消息的格式类似于 0x43 0x0B 0x00 0x06 0xA2 0x03 0x03 0x00 0x01 0x01 0x0A 0x0B 0x0B 0xE6 0x0D 其中以 0x43 开头并以 0x0D 结尾。所以,这意味着每次缓冲区被填满时,根据上述消息格式,它可以有不同的内容顺序。

static const int BufferSize = 1024;
byte buffer[BufferSize];
  1. 解析此缓冲区中的传入消息的最佳方法是什么?
  2. 由于我来自 Java 和 .NET,将每个提取的消息作为对象的最佳方法是什么?上课可以解决吗?
  3. 我创建了一个单独的类来解析缓冲区,如下所示,我的方向是否正确?

#include<parsingClass.h>
class A
{
   parsingClass ps;
public:
   parsingClass.parse(buffer, BufferSize);
}

【问题讨论】:

  • 谢谢,我正在尝试将它们放入代码样式中。

标签: c++ parsing buffer


【解决方案1】:
class ReturnMessage{
    char *message; 
    public:
    char *getMessage(unsigned char *buffer,int count){
         message = new char[count];
         for(int i = 1; i < count-2; i++){
            message[i-1] = buffer[i];
         }
         message[count-2] = '\0';
         return message;
    }
};
class ParserToMessage{
static int BufferSize = 1024;
unsigned char buffer[BufferSize];
unsigned int counter;
public:
  static char *parse_buffer()
  {
     ReturnMessage rm;
     unsigned char buffByte;
     buffByte = blueToothGetByte(); //fictional getchar() kind of function for bluetooth
     if(buffByte == 0x43){
        buffer[counter++] = buffByte;
        //continue until you find 0x0D
        while((buffByte = blueToothGetByte()) != 0x0D){
            buffer[counter++] = buffByte;
        }
     }
     return rm.getMessage(buffer,counter);
   }
};

【讨论】:

    【解决方案2】:

    您可以将解析器作为“ProtocolUnit”类的方法吗?该方法可以将缓冲区指针/长度作为参数,并返回一个 int 值,指示它在正确组装完整协议单元之前从缓冲区消耗了多少字节,或者如果它需要来自下一个缓冲区的更多字节,则返回 -1。

    一旦你有了一个完整的 ProtocolUnit,你就可以用它做你想做的事(例如,将它排入某个处理线程),并为剩余的字节/下一个缓冲区创建一个新的。

    【讨论】:

      【解决方案3】:

      我的 C++ 项目有一个可以是任意大小的缓冲区

      我注意到的第一件事是您对缓冲区大小进行了硬编码。如果尝试将大于您指定大小的数据读取到缓冲区中,您将面临缓冲区溢出的危险。

      如果可能,请保持缓冲区大小动态,并根据要接收到缓冲区中的数据大小创建字节数组。在创建字节数组之前,请尝试通知字节数组所在的对象传入的缓冲区大小。

      int nBufferSize = GetBufferSize();
      UCHAR* szByteArray = new UCHAR[nBufferSize];
      

      解析此缓冲区中的传入消息的最佳方法是什么?

      您在正确的路线上,因为您已经创建并正在使用解析器类。我建议使用memcpy 一次将单个数据项从缓冲区复制到您选择的变量。在这一点上不知道你的意图的更广泛背景,我不能补充太多。

      既然我来自 Java 和 .NET,那么最好的制作方法是什么 每个提取的消息都作为一个对象?类可以解决吗?

      根据您从缓冲区读取的数据的复杂性以及您的计划,您可以使用类或结构。如果您不需要使用此数据创建为其他对象提供服务的对象,则可以使用结构。当您的需求不那么复杂时,结构体非常棒,而一个完整的类可能是多余的。

      我已经创建了一个单独的类来解析缓冲区,如下所示,我 我的方向是对的吗?

      我想是的。

      希望对初学者有所帮助!

      【讨论】:

        【解决方案4】:

        “我应该如何解析”这个问题很大程度上取决于如何您想要解析数据。您的问题缺少两点:

        1. 究竟如何接收数据?你提到蓝牙,但什么是编程媒介?你是从套接字读取的吗?你有其他类型的API吗?您是一次接收一个字节还是分块接收它?
        2. 处理您收到的数据的规则是什么?大多数数据以某种方式或固定字段长度分隔。在您的情况下,您提到它可以是任意长度,但除非您解释 如何 要解析它,否则我无能为力。

        我会提出的一个建议是将缓冲区的类型更改为使用std::vector

        std::vector<unsigned char> buffer(normalSize)
        

        您应该选择normalSize 来设置您最常观察到的传入消息的大小。向量会随着您将项目推送到其上而增长,因此,与您创建的数组不同,如果您收到大消息,您无需担心缓冲区溢出。但是,如果您确实超出了 normalSize 的覆盖范围,则该向量将重新分配足够的内存来满足您的扩展需求。这可能很昂贵,因此您不想经常这样做。

        您使用向量的方式与使用数组的方式几乎相同。一个关键区别是您可以简单地将元素推到向量的末尾,而不必保留一个正在运行的指针。所以假设你一次从蓝牙源收到一个 int,你的代码可能看起来像这样:

        // Clear out the previous contents of the buffer.
        buffer.clear();
        
        int elem(0);
        // Find the start of your message. Throw away elements
        // that we don't need.
        while ( 0x43 != ( elem = getNextBluetoothInt() ) );
        
        // Push elements of the message into the buffer until
        // we hit the end.
        while ( 0x0D != elem )
        {
            buffer.push_back( elem );
        }
        buffer.push_back( elem ); // Remember to add on the last one.
        

        关键的好处是,无论推送的字符数是 10 还是 10,000,数组都会自动调整向量的大小,而无需您这样做。

        【讨论】:

        • 你能给我一个简单的例子,我如何在这种情况下使用矢量。
        • @pima.developer:我很乐意这样做,但正如我在回答中所说,在不确切知道你在做什么的情况下,准确地说有点棘手。我已经添加了有关如何捕获向量中的数据的更多详细信息,但至于您希望如何解析它,恐怕还不够开。
        猜你喜欢
        • 2021-11-13
        • 2018-04-09
        • 1970-01-01
        • 2017-10-08
        • 1970-01-01
        • 2020-04-26
        • 2013-04-01
        • 2011-08-25
        • 2018-11-21
        相关资源
        最近更新 更多