首页 文章

如何解析unsigned char数组到数值数据

提问于
浏览
1

我的问题设置如下:

  • 我有一个源将UDP数据包发送到我的接收计算机

  • 接收计算机接收UDP数据包并将其接收到 unsigned char *message .

我可以使用逐字节打印数据包

for(int i = 0; i < sizeof(message); i++) {
    printf("0x%02 \n", message[i];
}

这就是我的地方!现在我想开始解析我收到的这些字节作为短路,整数,长整数和字符串 .

我写了一系列函数,如:

short unsignedShortToInt(char[] c) {
    short i = 0;
    i |= c[1] & 0xff;
    i <<= 8;
    i |= c[0] & 0xff;
   return i;
}

解析字节并将它们转换为整数,长整数和短整数 . 我可以使用 sprintf() 从字节数组创建字符串 .

我的问题是 - 's the best way to get the substrings from my massive UDP packet? The packet is over 100 character in lengths, so I'喜欢将 message[0:6]message[20:22] 传递给这些变体实用程序函数的简单方法 .

可能的选择:

  • 我可以使用 strcpy() 为每个函数调用创建一个临时数组,但这看起来有点乱 .

  • 我可以将整个数据包转换为字符串并使用 std::string::substr . 这看起来不错,但我担心将无符号字符转换为有符号字符(字符串转换过程的一部分)可能会导致一些错误(可能这种担心是没有根据的?) .

  • 也许是另一种方式?

所以我问你,stackoverflow,推荐一个干净,简洁的方法来完成这个任务!

谢谢!

3 回答

  • 0

    为什么不使用proper serialization ?

    MsgPack

    你需要一个如何区分消息的方案 . 例如,你可以使它们成为self-describing,类似于:

    struct my_message {
      string protocol;
      string data;
    };
    

    并根据协议调度解码 .

    您最有可能最好使用经过测试的序列化库,而不是发现您的系统容易受到缓冲区溢出攻击和故障的影响 .

  • 1

    我认为你有两个问题需要解决 . 首先,您需要确保在从字符缓冲区中提取整数数据后,它们在内存中正确对齐 . 接下来,您需要确保提取后整数数据的正确字节顺序 .

    对齐问题可以通过__44819_来解决,该 union 包含叠加在正确大小的字符数组上的整数数据类型 . 可以使用标准 ntohs()ntohl() 函数来解决网络字节顺序问题 . 这仅在发送软件也使用由这些函数的反转产生的标准字节顺序时才有效 .

    见:http://www.beej.us/guide/bgnet/output/html/multipage/htonsman.html

    以下是您可能会发现有用的一些UNTESTED函数 . 我认为他们应该做你想做的事情 .

    #include <netinet/in.h>
    
    /**
     * General routing to extract aligned integral types
     * from the UDP packet.
     *
     * @param data Pointer into the UDP packet data
     * @param type Integral type to extract
     *
     * @return data pointer advanced to next position after extracted integral.
     */
    template<typename Type>
    unsigned char const* extract(unsigned char const* data, Type& type)
    {
        // This union will ensure the integral data type is correctly aligned
        union tx_t
        {
            unsigned char cdata[sizeof(Type)];
            Type tdata;
        } tx;
    
        for(size_t i(0); i < sizeof(Type); ++i)
            tx.cdata[i] = data[i];
    
        type = tx.tdata;
    
        return data + sizeof(Type);
    }
    
    /**
     * If strings are null terminated in the buffer then this could be used to extract them.
     *
     * @param data Pointer into the UDP packet data
     * @param s std::string type to extract
     *
     * @return data pointer advanced to next position after extracted std::string.
     */
    unsigned char const* extract(unsigned char const* data, std::string& s)
    {
        s.assign((char const*)data, std::strlen((char const*)data));
        return data + s.size();
    }
    
    /**
     *  Function to parse entire UDP packet
     *
     * @param data The entire UDP packet data
     */
    void read_data(unsigned char const* const data)
    {
        uint16_t i1;
        std::string s1;
        uint32_t i2;
        std::string s2;
    
        unsigned char const* p = data;
    
        p = extract(p, i1); // p contains next position to read
        i1 = ntohs(i1);
    
        p = extract(p, s1);
    
        p = extract(p, i2);
        i2 = ntohl(i2);
    
        p = extract(p, s2);
    }
    

    希望有所帮助 .

    EDIT:

    我编辑了示例以包含字符串 . 它在很大程度上取决于字符串在流中的存储方式 . 此示例假定字符串是以null结尾的c字符串 .

    EDIT2:

    Whoopse,根据问题更改了代码以接受 unsigned 字符 .

  • 1

    如果数组长度只有100个字符,则只需创建一个 char buffer[100]queue ,这样就不会错过处理任何消息 .

    接下来你可以像你描述的那样索引那个缓冲区,如果你知道了消息的结构,那么你就知道了索引点 .

    接下来你可以 union 类型,即

    union myType{
        char buf[4];
        int x;
     }
    

    如果你需要的话,从char给你一个int作为int的值

相关问题