[Design] Aus char/byte Array (Socket Empfangspuffer) structs extrahieren
-
Hi,
ich bekomme von einem Sensor kontinuierlich Messwerte (floats). Jeweils vier davon gehören immer zusammen (= Quaternion).
Die Verbindung zwischen PC und Sensor läuft über Bluetooth (Serial Port Profile) und einen Socket.Könnte man die Extraktion der Quaternionen aus dem Byte-Strom eleganter machen, als wie bisher (siehe Code)?
Endianess, Network-Byte-Order, Datentyp-Größenunterschiede sollen erstmal keine Rolle spielen. Alles bisher nur auf Windows 7, Visual Studio 2010.
struct Quaternion { float x0, x1, x2, x3; }; ... std::array<char, 4096> rbuffer; for (;;) { err = recv(s, &rbuffer[0], rbuffer.size(), 0); // ... error handling .. for (auto it = rbuffer.begin(); it != rbuffer.end(); std::advance(it, sizeof(Quaternion)) { Quaternion q; std::memcpy(&(*it), &q, sizeof(Quaternion)); handleQuaternion(q); //ggf. std::vector<Quaternion> + handleQuaternionVector outside loop } }Danke!
rbd
-
Du gehst davon aus, dass du immer den gesamten Puffer voll liest, worauf du dich allerdings nicht verlassen kannst:
http://msdn.microsoft.com/en-us/library/ms740121(v=vs.85).aspxWarum liest du eigentlich in einen Puffer, wenn du danach eh nur in die Struktur kopierst? Dann kannste auch gleich in den struct-Speicherbereich lesen.
-
struct Quaternion { float x0, x1, x2, x3; }; ... std::array<char, 4096> rbuffer; for (;;) { err = recv(s, &rbuffer[0], rbuffer.size(), 0); // error handling unsigned int Available = err; unsigned int Offset = 0; while( Available >= sizeof( Quaternion ) ) { Quaternion* Current = reinterpret_cast<Quaternion*>( rbuffer[Offset] ); handleQuaternion( *Current ); Offset += sizeof( Quaternion ); Available -= sizeof( Quaternion ); } }Du hast allerdings noch ein anderes Problem, du gehst nämlich davon aus, dass immer komplette Quaternion Daten gelesen werden. Das garantiert TCP/IP aber nicht, aufgrund der Protokolleigenschaften dürfen Pakete auch fragmentiert werden. Das könnte zur Folge haben (Empfang von 4 Quaternionen), dass der erste recv Aufruf 16 Bytes liest (1 komplette Quaternion), der zweite und dritte Aufruf liefern aber jeweils 24 Byte. Damit wären alle Daten übertragen (64 Byte, TCP/IP hat seinen Job korrekt erledigt), aber du kommst in´s Stolpern.
Du brauchst einen FIFO, in den hinten die gelesenen Daten angehängt werden und die behandelten Daten von vorne gelöscht werden.
-
Erstmal danke für eure Antworten und Hinweise.
Ihr habt Recht, ich müsste prüfen, wieviel wirklich im Puffer ist.
@XSpille:
Wegen der Zweiteilung 1) in Puffer 2) dann in structs: Ich dachte, dass es da vielleicht einige elegante Methode mittels Iteratoren gibt. Quasi immer über Block von 4 Floats iterieren und dass dann in ein Quaternion schreiben. Ähnlich wie man es mitistream_iteratormachen würde.@DocShoe: Fragmentierung dürfte nicht das Problem sein, die Übertragung läuft nicht mittels TCP/IP, sondern über serielle Schnittstelle (Bluetooth: Serial Port Profile). Unvollständig wird es IMHO doch erst, wenn die Verbindung abbricht. Da müsste man sich dann drum kümmern und den Rest wegwerfen.