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

时间:2010-04-28 12:15:25

标签: c++ sockets

我目前正在创建一个类来创建和读出通过网络发送的数据包,到目前为止,我已经使用了16位和8位整数(无符号但仍然)。

现在问题是我已经尝试了很多方法来复制它,但不知何故_buffer被破坏,它被分割,或结果是错误的。

如果有人能给我展示一个有效的例子,我会很感激。

我目前的代码可以在下面看到。

谢谢,Xeross

主要

#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_

3 个答案:

答案 0 :(得分:5)

由于你正在为你的缓冲区使用std :: vector,你也可以让它跟踪写入位置本身,避免不得不手动调整它的大小。您还可以使用函数模板避免编写add函数的多个重载:

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

现在您可以将任何POD类型写入缓冲区。

隐式:

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

或明确地说:

o.write<int>(5);

要从缓冲区读取,您需要跟踪读取位置:

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;
}

您需要显式传递要读取的类型参数。即。

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

警告:我经常使用这种模式,但由于我在脑海中输入这个模式,因此代码中可能存在一些错误。

编辑:我刚刚注意到您希望能够将字符串或其他非POD类型添加到缓冲区。您可以通过模板专业化来实现:

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

这告诉编译器:如果使用字符串类型调用add,请使用此函数而不是泛型add()函数。

并阅读字符串:

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

答案 1 :(得分:1)

您可以使用std::string作为内部缓冲区,并在添加新元素时使用append()

因此添加字符串或const char *将是微不足道的。

添加/编写uint8可以将其转换为char,将uint16写入char *,其长度为sizeof(uint16_t)。

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

阅读uint16:

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

答案 2 :(得分:0)

当您只添加了4个字符时,您似乎试图从缓冲区中打印出10个字节,因此您正在运行向量的末尾。这可能会导致你的段错误。

此外,您的printf正在尝试使用%x将字符打印为unsigned int。您需要使用static_cast<unsigned>(packet._buffer[i])作为参数。

文体: Packet packet = Packet();可能会导致构造两个对象。只需使用Packet packet;

即可

通常尽量避免使用受保护的属性(受保护的方法很好),因为它们会减少类的封装。