Sehr langer String



  • TyRoXx schrieb:

    Sieht nach UDP aus, da ist ein Ankommen der Pakete gar nicht garantiert. Ist hier aber nicht das größte Problem.

    str_rec += strDataBuffer;
    

    Woher soll += die Anzahl der gerade empfangenen Bytes kennen?

    Muss es das?(ernstgemeinte Frage) Bisher hatte es bei Dateien unter 1MB geklappt. Ich weiß nicht genau wie der operator += definiert ist, aber durch das memset davor, passt es doch (insofern die 0 als Delimiter dient)?

    TyRoXx schrieb:

    recvfrom(_sock, strDataBuffer, 1023, 0, 0, 0);
    

    Du meinst wohl 1024.

    Eh sollte 1024 werden. Ich habe nen define dafür. Wollte aber (da unwichtig) hier nicht posten und habe mich verschrieben.

    Und die Sache wird per TCP geschickt (nur per localhost). Ich weiß deshalb, dass alles angekommen ist, da die erhaltenen Bytes der Größe der Originaldatei entsprechen.



  • Shade Of Mine schrieb:

    str_rec += strDataBuffer;

    Was wenn in strDataBuffer eine 0 vorkommt?

    und recvfrom heisst UDP und UDP garantiert dir die Uebertragung nicht...

    Dann ist die 0 aber ein char. Und die '0' ist sozusagen eine 48 als int. Gibt also daher eig. keine Probleme.



  • SoM meint der char-Wert 0.



  • Was passiert den in diesem Fall? Wäre dies dann die Nullterminierung, so dass ich die nachfolgenden Zeichen vergessen kann (da operator += bis \0 durchläuft)?

    Anscheinend hatte ich bisher mit meinen Dateien soviel Glück, dass mir dieser Fall nicht untergekommen ist.



  • build schrieb:

    Was passiert den in diesem Fall? Wäre dies dann die Nullterminierung, so dass ich die nachfolgenden Zeichen vergessen kann (da operator += bis \0 durchläuft)?

    Ja.
    deshalb:
    str_rec.append(strDataBuffer, bytes_rec);

    wobei es natuerlich besser waere das ganze ohne kopieren zu machen.
    Und nebenbei bemerkt: du checkst nicht auf Fehler beim recvfrom.



  • build schrieb:

    Was passiert den in diesem Fall? Wäre dies dann die Nullterminierung, so dass ich die nachfolgenden Zeichen vergessen kann (da operator += bis \0 durchläuft)?

    Ja. Bzw: Ich glaube, es gibt gar keinen operator += (char const*), sondern nur einen operator += (string), bei dem die implizite Konvertierung über den Konvertierungs-Ctor greift. Aber für den Code ist das letztendlich egal.



  • Kellerautomat schrieb:

    Ich glaube, es gibt gar keinen operator += (char const*)

    doch.
    das ist std::string.
    da gibts alles.

    in manchen Implementierungen gibts auch eine koche_kaffee() Funktion.



  • Ich bin jetzt soweit:

    #define MAX_PACKET_SIZE 1024
    .
    .
    .
    	char	strDataBuffer[MAX_PACKET_SIZE]; // Unsere Daten
    
    	// Alle Pakete empfangen
    	size_t bytes_rec = 0;
    	size_t bytes_recv_total = 0;
    	std::string str_rec;
    	std::list<std::string> str_list;
    
    	do
    	{
    		memset(strDataBuffer, 0, MAX_PACKET_SIZE);
    		bytes_rec = recvfrom(_sock, strDataBuffer, MAX_PACKET_SIZE, 0, 0, 0);
    
    		// Alles gut gelaufen?
    		if(bytes_rec == SOCKET_ERROR)
    			return; // Na toll, ein Fehler
    
    		str_rec.append(strDataBuffer);
    
    		// Bei zuvielen Zeichen, den aktuellen String in eine Liste einfuegen
    		// Danach leeren
    		if(str_rec.length() >= str_rec.max_size()-MAX_PACKET_SIZE) 
    		{
    			str_list.push_back(str_rec);	// Hinten anfügen
    			str_rec.clear();			
    		}
    
    		bytes_recv_total += bytes_rec;
    	}
    	while(bytes_rec != 0);
    

    Jetzt bin ich soweit, dass ich aus diesen vielen Teilstrings einen großen CString erstellen möchte.
    Deshalb würde dieser Ansatz gehen?

    char *buffer = new char[bytes_rec];	// Ausgabepuffer
    	memset(buffer, 0, bytes_rec);
    
    	for(std::list<std::string>::const_iterator it = str_list.begin(); it != str_list.end(); it++)
    	{
    		sprintf(buffer, "%s%s", buffer, it->c_str());
    	}
    


  • str_rec.append(strDataBuffer);

    da hast du immernoch das selbe Problem.



  • Habs jetzt so gelöst und es funktioniert zumindest teilweise:

    for(int i = 0; i < MAX_PACKET_SIZE; i++)
    	str_rec += strDataBuffer[i];
    

    Bei Textdateien funktioniert dies wunderbar. Bei einem 4MB großen Bild, bekomme ich 1,5KB zuviel. Kann dies immernoch am operator+= liegen?



  • build schrieb:

    for(int i = 0; i < MAX_PACKET_SIZE; i++)
    	str_rec += strDataBuffer[i];
    

    Ich habe dir die Lösung doch schon gepostet:

    str_rec.append(strDataBuffer, bytes_rec);

    Bei deiner Schleife hast du nämlich das Problem: was passiert wenn du weniger als MAX_PACKET_SIZE an Daten bekommst? Dann füllst du mit 0 auf. Und das könnte zB deine 1,5k zuviel sein.



  • Oh das habe ich komplett übersehen. Deswegen hier ein verspätetes Danke!
    Und was ist in dem Fall, wie du beschrieben hast, dass die Datei den char-Wert 0 enthält? Den meine Dateien sind zwar gleich groß, haben aber die md5 Summen stimmen nicht überein.



  • build schrieb:

    Oh das habe ich komplett übersehen. Deswegen hier ein verspätetes Danke!
    Und was ist in dem Fall, wie du beschrieben hast, dass die Datei den char-Wert 0 enthält? Den meine Dateien sind zwar gleich groß, haben aber die md5 Summen stimmen nicht überein.

    std::string kann 0 werte enthalten. Die Frage ist, wie du die Daten dann in die Datei schreibst.

    Kommen denn die richtigen Anzahl Bytes jetzt an?



  • Ja die angekommenen Byte passen mit den gesendeten (und der Originaldatei) überein.
    Das Reinschreiben übernimmt die fstream.

    // pb.pData->data sind die durch recv erhaltenen Daten
    // pb.pData->nlength sind die durch recv erhaltenen Anzahl an Bytes des Datensatzes
    std::fstream file(filename, std::ios::out | std::ios::binary);
    
    file.write(pb.pData->data, pb.pData->nlength);
    
    file.close();
    


  • Und wie bekommst du pData->data?
    Da muss ja wieder irgendwo was kopiert werden.

    Hast du auch die Dateien korrekt als binary geöffnet und nicht als Text?



  • Datei öffnen:

    /** Unsere eigentlichen Daten */
    struct PacketTransmission
    {
    	char *data;			// Daten an sich
    	size_t nlength;			// Dateigroeße
    };
    
    FILE *fp = fopen(pb.filename.c_str(), "rb");
    
    // Dateigroese herausbekommen
    fseek(fp, 0, SEEK_END);
    int length = ftell(fp);
    rewind(fp);
    
    if(pb.pData == NULL)
    	pb.pData = new PacketTransmission;
    
    pb.pData->nlength = length;
    
    pb.pData->data = new char[length];
    
    fread(pb.pData->data, length, 1, fp);
    
    fclose(fp);
    

    Setzen eines Strings

    void Packet::SetString(std::string strData)
    {
    	if(pb.pData == NULL)
    	{
    		pb.pData = new PacketTransmission;
    		pb.pData->data = NULL;
    	}
    
    	if(pb.pData->data == NULL)
    	{
    		pb.pData->data = new char[strData.length()];
    		pb.pData->nlength = strData.length();
    		strcpy(pb.pData->data, strData.c_str());
    	}
    	else
    	{
    		delete pb.pData->data;
    
    		pb.pData->data = new char[strData.length()];
    		pb.pData->nlength = strData.length();
    		strcpy(pb.pData->data, strData.c_str());
    	}
    }
    

    Kann es sein, dass es daran liegt, dass ich nur ein send hab, welches mehrere MB rüberschickt und dadurch Unmengen an Fehler entstehen können?



  • strcpy(pb.pData->data, strData.c_str());

    hier hast du wieder das Problem mit den 0 Bytes.
    du brauchst hier memcpy

    Das Problem ist, du hast keinen echten C String. Ein C String ist nämlich dadurch definiert, dass er mit einem 0 Byte beendet wird. Wenn du binärdaten überträgst ist das aber nicht gegeben und du musst immer die größe mitangeben.

    Warum mischst du C und C++ eigentlich so?

    PS:
    delete pb.pData->data;
    das muss
    delete [] pb.pData->data;
    lauten.



  • Shade Of Mine schrieb:

    strcpy(pb.pData->data, strData.c_str());

    hier hast du wieder das Problem mit den 0 Bytes.
    du brauchst hier memcpy

    Das Problem ist, du hast keinen echten C String. Ein C String ist nämlich dadurch definiert, dass er mit einem 0 Byte beendet wird. Wenn du binärdaten überträgst ist das aber nicht gegeben und du musst immer die größe mitangeben.

    Warum mischst du C und C++ eigentlich so?

    PS:
    delete pb.pData->data;
    das muss
    delete [] pb.pData->data;
    lauten.

    Ah nochmal ein sehr sehr großes Danke! Endlich funktioniert es!
    Das Vermischen ist eig. im Nachhinein enstanden, da ich anfangs nur C++ genutzt habe und testen wollte, ob es evtl. am fstream / string lag.

    MD5 stimmt jetzt auch komplett überein.

    Nochmal ein großer Dank an alle!


Anmelden zum Antworten