Seite 1 von 1

Struct über Socket klappt nit....

Verfasst: Fr Mär 20, 2009 11:38 am
von Jside
So, jetzt wollte ichs mal testen, soweit läufts, kein Segmenation Fault o.a., allerdings klappt das Übertragen nicht, bei Dateien muss man diese via fgetc einzeln Zeichen für Zeichen übertragen...aber wie mache ich das bei structs, ohne, das der Server immer warten muss, das alles da ist ...wobei andere Clienten das wiederrum stören könnten!!??

Client:

Code: Alles auswählen

     Player_t iam;
     iam.IP = "127.0.0.1";
     iam.Name = "Ich";
     iam.x = 12;
     iam.y = 32;
     iam.z = 8;
     write(socket_nummer, iam, sizeof(iam));
Server:

Code: Alles auswählen

        Player_t try;
        read(client_socket,try,sizeof(try));
        printf("***INFO: X:%d,Y:%d,Z:%d, Name:%s\n",try.x,try.y,try.z,try.Name);
Das übertragen ansich klappt zwar, ich bekomme aber nur wischwasch an:
Bild

Hat jemand eine Idee?

Re: Struct über Socket klappt nit....

Verfasst: Fr Mär 20, 2009 3:09 pm
von nufan
Ich hab mal in meinem Buch weitergeblättert (bin noch nicht ganz so weit) und da wird die Struktur immer als Pointer übergeben.
Player_t ist doch eine "echte" Struktur und kein Pointer darauf, oder?

Also...

Code: Alles auswählen

write(socket_nummer, &iam, sizeof(iam));
bzw.

Code: Alles auswählen

read(client_socket,&try,sizeof(try));
Sieht man auch am Prototypen.

Auch in der SDL-Funktion wird die Adresse verwendet.

Re: Struct über Socket klappt nit....

Verfasst: Fr Mär 20, 2009 3:18 pm
von Jside
Player_t ist doch eine "echte" Struktur und kein Pointer darauf, oder?
Player_t ist eine direkte typedef struct {} Player_t

Danke, bis auf Strings klappt jetzt alles...
Bild

Soll ich die Strings jetzt am besten in int Konvertieren, oder mach ich immernoch irgendwas falsch?

Re: Struct über Socket klappt nit....

Verfasst: Fr Mär 20, 2009 3:21 pm
von nufan
Jside hat geschrieben:Danke, bis auf Strings klappt jetzt alles...
Bild

Soll ich die Strings jetzt am besten in int Konvertieren, oder mach ich immernoch irgendwas falsch?
Nunja...

Code: Alles auswählen

iam.Name = "Ich";
Hast du '=' überladen (C++)? Wenn nicht strcpy verwenden.

Re: Struct über Socket klappt nit....

Verfasst: Fr Mär 20, 2009 3:22 pm
von Dirty Oerti
Da Strings dynamisch wachsen können besteht ein String nicht nur aus der Klasse "String". Diese Klasse reserviert sich durch ihre Benutzung auch Speicher.
Um also eine Stringklasse übertragen zu können musst du die kompletten Daten übertragen.
Das wird etwas schwer, deswegen solltest du wohl Strings zu Chararrays konvertieren (string.c_str() ).

Was mir auch noch einfällt: Die Konvertierung in Network Byte Order und zurück nimmst du ja hoffentlich vor, oder?

Re: Struct über Socket klappt nit....

Verfasst: Fr Mär 20, 2009 11:11 pm
von fat-lobyte
Ä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.

Re: Struct über Socket klappt nit....

Verfasst: Sa Mär 21, 2009 10:11 am
von Jside
Also was Little und Big Endian sind, weiß ich(von meinem MIPS Rechnern aus), aber nicht, das das in diesem Zusammenhang relevant ist ;)
Hat mir aufjedemfall schonmal weitergeholfen, danke!