[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).aspx

    Warum 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 mit istream_iterator machen 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.


Anmelden zum Antworten