Ähem...
Also erstens:
Das ist klar dass die Strings nicht richtig übertragen werden! Dein Struct enthält wahrscheinlich nur einen Zeiger auf deinen String, nicht aber den String selbst. Soll read() etwa allen Zeigern folgen und die auch noch mitkopieren? Das musst du schon extra sagen.
Zweitens: Was du tust ist ziemlich schlecht. Structs ohne konvertierung auf das Kabel zu schicken KANN funktionieren, muss aber nicht. Wenn dein Client und dein Server nämlich auf verschiedenen Systemen laufen, oder auch nur mit verschiedenen Compilern kompiliert wurden, dann ist es gut möglich dass das "byte alignment" nicht mehr gleich ist:
Alle structs speichern zwar die deklarierten Werte hintereinander, allerdings ist es dem Compiler erlaubt zu "pad with zeros", also deine Variablen zur optimierung mit nullen auf 4 Byte (oder was auch immer!) zu bringen.
Außerdem gibts noch das problem mit der Byte Order: die "meisten" Computer verwenden "little endian", es gibt aber auch noch manche mit "big endian". Wenn du dir sicher bist dass deine Programme nur auf "little endian"-Systemen laufen werden brauchst du nichts zu tun. Wenn du "big endian" auch noch unterstützen willst, solltest du deine Lokalen integers auf eine bestimmte byte order bringen (traditionell ist das host byte order oder big endian) und dann bei dem empfänger je nach system wieder zurückkonvertieren.
Kurzum, ich empfehle eine kurze Funktion, die allen Eventualitäten vorbeugt. Das kannst du dadurch machen, dass du einen wirklichen "buffer", also einen durchgehenden Speicherblock allokierst und dort deine Werte genau definiert reinschreibst.
Hier mal sowas in C++:
Code: Alles auswählen
// alle datentypen peinlich genau definieren,
// und nicht annehmen das sie auf allen systemen gleich sind!!
typedef signed char byte_t;
typedef int int4b_t;
// nicht abschrecken lassen, die Funktion tut genau das was der name sagt:
// es dreht einfach nur die bytes um.
template <typename T>
inline T reversebytes(T x)
{
std::reverse(
reinterpret_cast<byte_t*>(&x),
reinterpret_cast<byte_t*>(&x) + sizeof(x)
);
return x;
}
#ifndef BIG_ENDIAN
template <typename T>
inline T htonx(T x) { return reversebytes(x); }
template <typename T>
inline T ntohx(T x) { return reversebytes(x); }
#else
template <typename T>
inline T htonx(T x) { return x; }
template <typename T>
inline T ntohx(T x) { return x; }
#endif
struct DatenStruct
{
int4b_t a;
byte_t b;
char* text;
};
const unsigned STRING_MAX = 255;
void* serializeStruct(const DatenStruct* daten)
{
byte_t* sendbuf, it;
// wie lang ist der String eigentlich?
size_t _textlength = strlen(text);
if (_textlength > STRING_MAX)
return NULL; // wir mögen keine zu großen strings!
byte_t textlength = _textlength;
// structgröße berechnen:
// Größe von a + Größe von b + ...
// Wir müssten beim empfänger eigentlich auch wissen, wie groß der string
// ist. fügen wir doch einfach noch eine variable mit der größe ein
std::size_t structsize =
sizeof(daten->a) + sizeof(daten->b) + sizeof(textlength) + textlength;
// speicher allokieren
sendbuf = (byte_t*) malloc(structsize);
// fehlerbehandlung
it = sendbuf;
//erstes feld ist a
((int4b_t*) it) = ntohx(daten->a); it += sizeof(int4b_t);
//zweites feld ist b
((byte_t*) it) = ntohx(daten->b); it += sizeof(byte_t);
// drittes feld ist die größe des strings (woher soll sons der empfänger
// wissen wie lang die nachricht ist?
strncpy((char*) it, daten->text, textlength);
return sendbuf;
}
Oder so ungefähr... Nicht kopieren und verwenden, bitte nur als hinweis verwenden.
Haters gonna hate, potatoes gonna potate.