Struct über Socket klappt nit....

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
Benutzeravatar
Jside
Beiträge: 377
Registriert: Di Nov 11, 2008 12:56 am

Struct über Socket klappt nit....

Beitrag von Jside » Fr Mär 20, 2009 11:38 am

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?

nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

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

Beitrag von nufan » Fr Mär 20, 2009 3:09 pm

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.

Benutzeravatar
Jside
Beiträge: 377
Registriert: Di Nov 11, 2008 12:56 am

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

Beitrag von Jside » Fr Mär 20, 2009 3:18 pm

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?

nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

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

Beitrag von nufan » Fr Mär 20, 2009 3:21 pm

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.

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

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

Beitrag von Dirty Oerti » Fr Mär 20, 2009 3:22 pm

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?
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

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

Beitrag von fat-lobyte » Fr Mär 20, 2009 11:11 pm

Ä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.

Benutzeravatar
Jside
Beiträge: 377
Registriert: Di Nov 11, 2008 12:56 am

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

Beitrag von Jside » Sa Mär 21, 2009 10:11 am

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!

Antworten