我目前正在创建一个类来创建和读出通过网络发送的数据包,到目前为止,我已经使用了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;
}
#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_
答案 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;
通常尽量避免使用受保护的属性(受保护的方法很好),因为它们会减少类的封装。