简体   繁体   English

将字符串或char数组添加到字节向量

[英]Adding a string or char array to a byte vector

I'm currently working on a class to create and read out packets send through the network, so far I have it working with 16bit and 8bit integers (Well unsigned but still). 我目前正在研究一个类,以创建和读取通过网络发送的数据包,到目前为止,我已经使用16位和8位整数(但无符号,但仍然)。

Now the problem is I've tried numerous ways of copying it over but somehow the _buffer got mangled, it segfaulted, or the result was wrong. 现在的问题是,我尝试了多种复制方法,但是_buffer被弄乱了,被隔离了,或者结果是错误的。

I'd appreciate if someone could show me a working example. 如果有人可以给我看一个可行的例子,我将不胜感激。

My current code can be seen below. 我当前的代码可以在下面看到。

Thanks, Xeross 谢谢,Xeross

Main 主要

#include <iostream>
#include <stdio.h>
#include "Packet.h"

using namespace std;

int main(int argc, char** argv)
{
    cout << "#################################" << endl;
    cout << "#       Internal Use Only       #" << endl;
    cout << "#     Codename PACKETSTORM      #" << endl;
    cout << "#################################" << endl;
    cout << endl;

    Packet packet = Packet();
    packet.SetOpcode(0x1f4d);

    cout << "Current opcode is: " << packet.GetOpcode() << endl << endl;

    packet.add(uint8_t(5))
          .add(uint16_t(4000))
          .add(uint8_t(5));

    for(uint8_t i=0; i<10;i++)
        printf("Byte %u = %x\n", i, packet._buffer[i]);

    printf("\nReading them out: \n1 = %u\n2 = %u\n3 = %u\n4 = %s",
        packet.readUint8(),
        packet.readUint16(),
        packet.readUint8());

    return 0;
}

Packet.h 数据包

#ifndef _PACKET_H_
#define _PACKET_H_

#include <iostream>
#include <vector>

#include <stdio.h>
#include <stdint.h>
#include <string.h>

using namespace std;

class Packet
{
    public:
        Packet() : m_opcode(0), _buffer(0), _wpos(0), _rpos(0) {}
        Packet(uint16_t opcode) : m_opcode(opcode), _buffer(0), _wpos(0), _rpos(0) {}

        uint16_t GetOpcode() { return m_opcode; }
        void SetOpcode(uint16_t opcode) { m_opcode = opcode; }

        Packet& add(uint8_t value)
        {
            if(_buffer.size() < _wpos + 1)
                _buffer.resize(_wpos + 1);

            memcpy(&_buffer[_wpos], &value, 1);
            _wpos += 1;

            return *this;
        }
        Packet& add(uint16_t value)
        {
            if(_buffer.size() < _wpos + 2)
                _buffer.resize(_wpos + 2);

            memcpy(&_buffer[_wpos], &value, 2);
            _wpos += 2;

            return *this;
        }

        uint8_t readUint8()
        {
            uint8_t result = _buffer[_rpos];
            _rpos += sizeof(uint8_t);
            return result;
        }
        uint16_t readUint16()
        {
            uint16_t result;
            memcpy(&result, &_buffer[_rpos], sizeof(uint16_t));

            _rpos += sizeof(uint16_t);
            return result;

        }

        uint16_t m_opcode;
        std::vector<uint8_t> _buffer;
    protected:

        size_t _wpos; // Write position
        size_t _rpos; // Read position
};

#endif // _PACKET_H_

Since you're using an std::vector for your buffer, you may as well let it keep track of the write position itself and avoid having to keep manually resizing it. 由于您在缓冲区中使用std :: vector,因此最好让它跟踪写入位置本身,而不必继续手动调整其大小。 You can also avoid writing multiple overloads of the add function by using a function template: 您还可以通过使用函数模板避免编写add函数的多个重载:

template <class T>
Packet& add(T value) {
    std::copy((uint8_t*) &value, ((uint8_t*) &value) + sizeof(T), std::back_inserter(_buffer));
    return *this;
}

Now you can write any POD type to your buffer. 现在,您可以将任何POD类型写入缓冲区。

implicitly: 隐式地:

int i = 5;
o.write(i);

or explictly: 或明确地:

o.write<int>(5);

To read from the buffer, you will need to keep track of a read position: 要从缓冲区读取,您将需要跟踪读取位置:

template <class T>
T read() {
    T result;
    uint8_t *p = &_buffer[_rpos];
    std::copy(p, p + sizeof(T), (uint8_t*) &result);
    _rpos += sizeof(T);
    return result;
}

You will need to explicitly pass a type parameter to read. 您将需要显式传递类型参数以进行读取。 ie

int i = o.read<int>();

Caveat: I have used this pattern often, but since I am typing this off the top of my head, there may be a few errors in the code. 警告:我经常使用这种模式,但是由于我是在脑海中反复键入此模式的,因此代码中可能存在一些错误。

Edit: I just noticed that you want to be able to add strings or other non-POD types to your buffer. 编辑:我只是注意到您希望能够将字符串或其他非POD类型添加到缓冲区。 You can do that via template specialization: 您可以通过模板专门化来实现:

template <>
Packet& add(std::string s) {
    add(string.length());
    for (size_t i = 0; i < string.length(); ++i)
        add(string[i]);
    return *this;
}

This tells the compiler: if add is called with a string type, use this function instead of the generic add() function. 这告诉编译器:如果使用字符串类型调用add,请使用此函数代替通用的add()函数。

and to read a string: 并读取一个字符串:

template <>
std::string read<>() {
    size_t len = read<size_t>();
    std::string s;
    while (len--)
        s += read<char>();
    return s;
}

You could use std::string as internal buffer and use append() when adding new elements. 您可以使用std::string作为内部缓冲区,并在添加新元素时使用append()

Thus adding strings or const char* would be trivial. 因此,添加字符串或const char *将是微不足道的。

Adding/writing uint8 can be done with casting it to char, writing uint16 - to char* with length sizeof(uint16_t). 添加/写入uint8可以通过将其强制转换为char,将uint16-写入具有长度sizeof(uint16_t)的char *来完成。

void write_uint16( uint16_t val )
{
    m_strBuffer.append( (char*)(&var), sizeof(val) );
}

Reading uint16: 读uint16:

uint16_t read_int16()
{
    return ( *(uint16_t*)(m_strBuffer.c_str() + m_nOffset) );
}

You appear to be attempting to print ten bytes out of the buffer when you've only added four, and thus you're running off the end of the vector. 当您仅添加四个字节时,您似乎正在尝试从缓冲区中打印十个字节,因此,您正在使用向量的末尾。 This could be causing your seg fault. 这可能会导致您的段错误。

Also your printf is trying to print a character as an unsigned int with %x. 另外,您的printf尝试使用%x将字符打印为无符号整数。 You need to use static_cast<unsigned>(packet._buffer[i]) as the parameter. 您需要使用static_cast<unsigned>(packet._buffer[i])作为参数。

Stylistically: Packet packet = Packet(); 从风格上讲: Packet packet = Packet(); could potentially result in two objects being constructed. 可能会导致构造两个对象。 Just use Packet packet; 只使用Packet packet;

Generally try to avoid protected attributes (protected methods are fine) as they reduce encapsulation of your class. 通常尝试避免使用受保护的属性(受保护的方法很好),因为它们会减少类的封装。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM