Protokoll schreiben
-
write
hängt einen Wert an undoverwrite
überschreibt den Wert an einer früheren Position.
Das sind Templates, damit das mit allen primitiven Datentypen funktioniert.
Die Methoden haben dann noch allgemeinere nicht-Template-Versionen, die beliebige Daten annehmen.
Falls dir das syntaktisch nicht klar ist, beschäftige dich nochmal mit C++ an sich.
-
Hallo nochmals,
das von dir (TyRoXx) implementierte Code hat folgenden Konstrukt:
`<32 bit> "dataID"<32 bit> Zeit
<32 bit> payload Länge
<N * 8 bit> payload `
Liege ich da richtig oder nicht? Was soviel heißt wie, mein Protokoll weist eine variable Länge auf.
Danke im Voraus!
-
Ja, der Header ist wie angegeben, die Paketlänge ist variabel (wie denn sonst).
-
Hallo TyRoXx ,
ich habe deinen Code eingetippt und wiederum verusucht die Standardwerte zu bekommen und bin daber auf ein paar kleine Fehler gestoßen. Nach deinem Code sind jeweils 32-Bit für die ID vergeben, das wiederum ein uint32 ist. Mit
std::string id; id.append(packet,0,4);
kann ich den String herauslesen. wie bekomme ich aus dieser wieder ein uint32 ?
-
TyRoXx ich hätte da noch eine Frage bzw. eine Bemerkung. Das Auslesen der Zahlenwerte für die ID funktioniert wunderbar in Bereich von 0-127 sobald die Zahl größer ist kommt Unfug heraus. Wie könnte dies behoben werden?
-
Beobachter01 schrieb:
std::string id; id.append(packet,0,4);
kann ich den String herauslesen. wie bekomme ich aus dieser wieder ein uint32 ?
Interessante Idee, aber den
string id
kann man sich sparen.
Du holst dir mit&packet[0]
einen Zeiger auf den Speicher und kopierst mitmemcpy
in die Variablen hinein. Um die nächste Variable zu erhalten, einfach den Zeiger erhöhen:std::string incoming; const char *position = &incoming[0]; const char * const end = position + incoming.size(); std::uint32_t dataId; if (position + sizeof(dataId) > end) { //unvollständiges Paket behandeln.. } std::memcpy(&dataId, position, sizeof(dataId)); position += sizeof(dataId); //nächster Wert genauso..
J.Wayne schrieb:
TyRoXx ich hätte da noch eine Frage bzw. eine Bemerkung. Das Auslesen der Zahlenwerte für die ID funktioniert wunderbar in Bereich von 0-127 sobald die Zahl größer ist kommt Unfug heraus. Wie könnte dies behoben werden?
Keine Ahnung, wie liest du denn aus?
-
Ich dachte memcpy gilt nur string bzw char* :S naja danke dir TyRoXx.
Wie liest man die Länge und den eingegebenen String aus. Mit Zeiger funktioniert es nicht so ganz!
-
Beobachter01 schrieb:
Ich dachte memcpy gilt nur string bzw char* :S naja danke dir TyRoXx.
Wie liest man die Länge und den eingegebenen String aus. Mit Zeiger funktioniert es nicht so ganz!Dann zeig mal deinen Ansatz.
-
uint32_t dataId; uint32_t timed; std::string payload; memcpy(&dataId, position, sizeof(dataId)); position +=sizeof(dataId); memcpy(&timed, position, sizeof(timed)); position +=sizeof(timed); memcpy(&payload, position, sizeof(payload));
Habe es so gemacht mit Zeiger und Co. Wie gesagt funktionieren die Ersten beiden Werte wunderbar, beim Dritten bekomme ich mit cout folgendes
1730(erster Wert) 1024(zweiter Wert) hallo ===========²²²² und ganz viele komische Zeichen im Anschluss. zu guter Letzt kommt ein Debug- Fehler
-
Hallo,
ich bekomme irgendwie es nicht hin nach der Versendung über TCP, dass packet wieder auszulesen. Bin irgendwie fürs programmieren nicht geeignet bzw der Umstieg von Java auf C++ war doch nicht so.
-
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); } }