Dynamischer array größe



  • Hallo,

    meine Frage ich möchte eine variable Länge eines Strings über TCP versenden. Ist es möglich auf der anderen Seite einen char array anzulegen der genau diese Textlänge besitzt?

    Bsp:

    std::string test ("bla bla bla");
    ....
    //länge des strings
    send(socket,reinterpret_cast<char*>(strlen(text.c_str())),strlen(text.c_str()),0);
    //versenden des eigentlichen Inhalts
    send(socket,text.c_str(),strlen(text.c_str()),0);
    
    //auf der Empfangsseite
    recv(socket,buf,256,0);
    int length = atoi(buf);
    //hier ein array mit der länge length
    char buffer[length];
    //anschließend Text Empfang
    recv(socket,buffer,length,0);
    

    oder habt ihr einen besseren Lösungvorschlag? 😕



  • J.Wayne schrieb:

    Hallo,

    meine Frage ich möchte eine variable Länge eines Strings über TCP versenden. Ist es möglich auf der anderen Seite einen char array anzulegen der genau diese Textlänge besitzt?

    Bsp:

    std::string test ("bla bla bla");
    ....
    //länge des strings
    send(socket,reinterpret_cast<char*>(strlen(text.c_str())),strlen(text.c_str()),0);
    //versenden des eigentlichen Inhalts
    send(socket,text.c_str(),strlen(text.c_str()),0);
    
    //auf der Empfangsseite
    recv(socket,buf,256,0);
    int length = atoi(buf);
    //hier ein array mit der länge length
    char buffer[length];
    //anschließend Text Empfang
    recv(socket,buffer,length,0);
    

    oder habt ihr einen besseren Lösungvorschlag? 😕

    Das geht nicht, weil length nicht konstant ist. Grundsätzlich ist das aber eine Art, es zu realisieren. Alternativ kannst Du den String auch in eine Sequenz gleichgroßer Blöcke zerlegen und ihn dann Stück für Stück verschicken. Dabei brauchst Du dann noch einen Marker für das Ende.



  • HI ist mir schon klar, dass dies ein Fehler spuckt. Ich habe versucht ein char* zu nehmen und darauf die length als Länge zu empfangen. Bei compilieren ist kein Fehler aufgetreten aber bei der Ausführung geht es nicht!



  • Eigentlich sollte das gar nicht compilieren, weil das hier nicht erlaubt ist:

    int length = atoi(buf);
    //hier ein array mit der länge length
    char buffer[length];
    

    Vermutlich benutzt Du einen Compiler, der C++ um C99-Features erweitert.
    Probier' es mal so:

    //senden
    std::ostringstream osstr;
    osstr << test.size();
    std::size_t const header_length = 12;
    char header[header_length] = {0};
    std::string const & access = osstr.str();
    if(access.size() < header_length)
    {
       std::copy(access.begin(), access.end(), header);
    }
    else
    {
       //problem
    }
    
    send(socket, header, header_length, 0);
    send(socket, test.c_str(), test.size(), 0);
    
    //empfangen
    char header[header_length];
    recv(socket, header, header_length, 0);
    std::istringstream isstr(header);
    std::size_t size = 0;
    isstr >> size;
    std::vector<char> buffer(size, 0);
    recv(socket, &buffer.front(), buffer.size(), 0);
    std::cout << std::string(buffer.begin(), buffer.end()) << std::endl;
    


  • Darf ich kurz fragen was du oben bei senden machst? Ich möchte nicht stur Code abtippen und mich später bei einer Funktionalität freuen.

    beim empfangen kann ich mir noch die einzelnen Sachen zusammenreimen 🙂



  • Tachyon danke dir es läuft! Könntest du eventuell noch eine kurz beschreiben was da alles passiert?! Danke!



  • Die wichtigste Zeile dürfte doch

    std::vector<char> buffer(size, 0);
    

    sein. Die 0 als zweiter Parameter ist redundant (legt fest, welchen Wert jeder char erhält, standard ist der Defaultwert eines Typen und dies entspricht bei char und anderen eingebauten PODs 0).
    Ein vector verwaltet seine Daten an einem Stück im Freispeicher. Die Freigabe erfolgt automatisch im Destruktor.

    Ansonsten: Was verstehst du nicht an Tachyons Code?



  • Verfolger schrieb:

    Tachyon danke dir es läuft! Könntest du eventuell noch eine kurz beschreiben was da alles passiert?! Danke!

    Im Prinzip macht der Code das, was Du beschrieben hast: Erst die Größe und dann die Daten versenden. Dann nach dem Empfang der Größe einen passenden Puffer anlegen und dort die Daten hineinlesen.
    Einfach mal nachlesen, was die einzelnen Dinge machen, z.B. hier.



  • //senden
    std::ostringstream osstr;
    osstr << test.size();
    std::size_t const header_length = 12;    //kann ich beliebigen Wert nehmen?
    char header[header_length] = {0};
    std::string const & access = osstr.str(); //Warum wird das gemacht??
    if(access.size() < header_length)
    {
       std::copy(access.begin(), access.end(), header); //auch das
    }
    else
    {
       //problem
    }
    
    send(socket, header, header_length, 0);
    send(socket, test.c_str(), test.size(), 0);
    
    //empfangen
    char header[header_length];
    recv(socket, header, header_length, 0);
    std::istringstream isstr(header);
    std::size_t size = 0;
    isstr >> size;
    std::vector<char> buffer(size, 0);
    recv(socket, &buffer.front(), buffer.size(), 0);
    std::cout << std::string(buffer.begin(), buffer.end()) << std::endl;
    

    Beim empfangen wird ein vector<char> angelegt der einen gewissen Puffer haben soll, das ich mit size zuweise. Diesen Teil habe ich verstanden. Oben ist kurz noch beschrieben was mir noch unklar ist.
    Danke 🙂



  • Verfolger schrieb:

    //senden
    std::size_t const header_length = 12;    //kann ich beliebigen Wert nehmen?
    

    Nein, und dies ist auch nicht sinnvoll. Wie groß ist die größte Zahl, die Du mit 12 Dezimalstellen darstellen kannst, und was meinst Du, wie sinnvoll es wäre, einen entsprechend großen Puffer beim Empfang anzulegen?

    Verfolger schrieb:

    std::string const & access = osstr.str(); //Warum wird das gemacht??
    if(access.size() < header_length)
    {
       //Warum wird das gemacht??
       //Damit begin() und end() hier Iteratoren auf das gleiche String-Objekt liefern
       //Hier wird der Inhalt des Strings im Stringstream (der die Größe als String enthält) in den Header kopiert
       std::copy(access.begin(), access.end(), header); //auch das
    }
    


  • Danke dir!

    //senden
    std::size_t const header_length = 12;    //kann ich beliebigen Wert nehmen?
    

    Ich habe nur gemeint ist das kein Overhead eine 12stellige Dezimalzahl, was zugleich eine 2^56 Bitzahl ist, zu verwenden?

    Beim empfangen wird ja ein Vektor angelegt, der die Größe von in header geschriebenen Wert enthält! Soweit ist es richtig nehme ich an anschließend wird in diesen Vektor die einzelnen Zeichen übergeben. Oder?

    Ich würde gern von Anfang an C++ richtig lernen und verstehen was die einzelne Schritte machen. Aus diesem Grund so viele Fragen 🙂



  • Verfolger schrieb:

    Danke dir!

    //senden
    std::size_t const header_length = 12;    //kann ich beliebigen Wert nehmen?
    

    Ich habe nur gemeint ist das kein Overhead eine 12stellige Dezimalzahl, was zugleich eine 2^56 Bitzahl ist, zu verwenden?

    Beim empfangen wird ja ein Vektor angelegt, der die Größe von in header geschriebenen Wert enthält! Soweit ist es richtig nehme ich an anschließend wird in diesen Vektor die einzelnen Zeichen übergeben. Oder?

    Ich würde gern von Anfang an C++ richtig lernen und verstehen was die einzelne Schritte machen. Aus diesem Grund so viele Fragen 🙂

    Nochmal der Teil zum Senden überarbeitet:

    //template zum ermitteln der Anzahl an Dezimalstellen fuer eine Zahl
    template <std::size_t N, std::size_t base=10>
    struct digits
    {
    	enum { value = 1 + digits<N/base, base>::value };
    };
    
    template <size_t base>
    struct digits<0, base>
    {
    	enum { value = 0 };
    };
    
    std::size_t const max_payload_size = (1u << 20u); //maximal ein MiB also 2^20 bytes
    std::size_t const header_size = digits<max_payload_size>::value; //noetige arraygroesse fuer header
    
    typedef char header_type[header_size+1]; //header type
    
    if(test.size() <= max_payload_size) //test enthaelt die Nutzdaten
    {
        //quasi wie gehabt
        std::ostringstream osstr;
        osstr << test.size();
        std::string const & access = osstr.str();
        header_type header = {0};
        std::copy(access.begin(), access.end(), header);
        send(socket, header, header_size, 0); 
        send(socket, test.c_str(), test.size(), 0); 
    }
    else
    {
        //problem
    }
    

    Hierbei gibt max_payload_size die maximal erlaubte Größe an (hier ein MiB). Das Template rechnet aus, wieviele Dezimalstellen die Zahl für die Größe hat (hier 7). Mit dem Wert wird dann das Array für den Header angelegt.
    Du gibst nun also direkt die maximal gewünschte Anzahl an Bytes an, die übertragen werden soll.


Anmelden zum Antworten