T
Die Komplettlösung für die Allgemeinheit:
#include <string>
#include <cstring>
#include <cassert>
#include <cstdint>
typedef std::string Buffer;
struct BinaryWriter
{
Buffer &buffer;
explicit BinaryWriter(Buffer &buffer)
: buffer(buffer)
{
}
void write(const char *data, size_t size)
{
buffer.append(data, data + size);
}
void overwrite(size_t position, const char *data, size_t size)
{
assert(position + size <= buffer.size());
std::memcpy(&buffer[position], data, size);
}
template <class POD>
void write(POD value)
{
write(reinterpret_cast<const char *>(&value), sizeof(value));
}
template <class POD>
void overwrite(size_t position, POD value)
{
overwrite(position, reinterpret_cast<const char *>(&value), sizeof(value));
}
void writeString32(const std::string &str)
{
write(static_cast<std::uint32_t>(str.size()));
write(str.data(), str.size());
}
};
struct PacketWriter : BinaryWriter
{
size_t sizePosition;
size_t payloadPosition;
PacketWriter(Buffer &buffer, std::uint32_t id, std::uint32_t time)
: BinaryWriter(buffer)
{
write(id);
write(time);
//die Position der Länge für spätere Korrektur speichern
sizePosition = buffer.size();
write(std::uint32_t(0));
//um die Länge des Inhaltes auszurechnen
payloadPosition = buffer.size();
}
void finish()
{
size_t currentPos = buffer.size();
std::uint32_t length = static_cast<std::uint32_t>(currentPos - payloadPosition);
overwrite(sizePosition, length);
}
};
struct BinaryReader
{
const char *begin, *pos, *end;
BinaryReader()
: begin(0)
, pos(0)
, end(0)
{
}
BinaryReader(const char *begin, const char *end)
: begin(begin)
, pos(begin)
, end(end)
{
}
size_t remaining() const
{
return (end - pos);
}
bool read(char *dest, size_t size)
{
if (size > remaining())
{
return false;
}
std::memcpy(dest, pos, size);
pos += size;
return true;
}
template <class POD>
bool read(POD &value)
{
return read(reinterpret_cast<char *>(&value), sizeof(value));
}
bool readString32(std::string &dest)
{
std::uint32_t length;
if (read(length))
{
dest.resize(length);
if (length)
{
return read(&dest[0], length);
}
return true;
}
return false;
}
};
struct PacketReader : BinaryReader
{
std::uint32_t id, time;
BinaryReader body;
PacketReader(const char *begin, const char *end)
: BinaryReader(begin, end)
{
}
bool parseHeader()
{
std::uint32_t length;
if (
read(id) &&
read(time) &&
read(length) &&
(remaining() >= length))
{
body.begin = body.pos = this->pos;
body.end = body.begin + length;
//Inhalt überspringen
this->pos += length;
return true;
}
return false;
}
};
#include <iostream>
using namespace std;
int main()
{
Buffer packet;
{
PacketWriter writer(packet, 123, 456);
std::string message = "hallo";
writer.writeString32(message);
writer.write<std::uint16_t>(42); //ja, hier können beliebige weitere Werte folgen
writer.finish();
//packet kann nun versendet werden..
}
//empfangen..
{
PacketReader reader(&packet[0], &packet[0] + packet.size());
if (!reader.parseHeader())
{
//nach dem nächsten receive nochmal versuchen..
cout << "Incomplete packet" << endl;
return 1;
}
std::string message;
reader.body.readString32(message); //Ergebnis ggf. prüfen
cout << message << endl;
std::uint16_t value;
reader.body.read(value);
cout << value << endl;
//das gelesene Paket aus dem Puffer entfernen.
//clear() ist ungeeignet, denn es können weitere Pakete im Puffer liegen.
const size_t parsed = (reader.pos - reader.begin);
packet.erase(
packet.begin(),
packet.begin() + parsed);
}
}