[WinSock] Dateien versenden (mal wieder)



  • Mahlzeit, Community 😉
    Hab seit langem mal wieder ein für mich undurchschaubares Problem ..
    Ich versende über ne Wrapper-Klasse Dateien via WinSock. Das funktioniert an sich auch, das Problem ist nur, dass irgendwas bei den Dateien fehlt ..
    Wenn ich z.B. ein Bild versende und das empfangene Bild dann öffne, fehlen die letzen Pixelreihen. Bei EXE-Dateien ähnlich. Die Datei wird normal verschickt, kommt normal an, aber wenn ich die dann öffnen will, kommt die Fehlermeldung, dass die Anwendungskonfiguration nicht korrekt ist. Die Versionsinformationen sowie das Icon für das Programm kommen allerdings ganz normal an, auch die Dateigrößen stimmen auf den Byte genau (laut der Anzeige unter "Einstellungen") ..

    Hier mal die Codesnippets zum Senden und Empfangen:

    // SENDEN
    
            pFile = fopen (sh.lpFile, "rb");
            char buffer[sh.iBlockSize];
    
            unsigned long fileSize = sh.iDataSize;
            while (fileSize >= sh.iBlockSize)
            {
                fread (buffer, sh.iBlockSize, 1, pFile);
                bytes = ::send (socket, buffer, sh.iBlockSize, 0);
                fileSize -= sh.iBlockSize;
            }
            if (fileSize)
            {
                fread (buffer, fileSize, 0, pFile);
                bytes = ::send (socket, buffer, fileSize, 0);
                fileSize = 0;
            }
    
            fclose (pFile);
    
    // EMPFANGEN
    
            pFile = fopen ("C:\\Dokumente und Einstellungen\\Administrator\\Eigene Dateien\\te2st3.jpg", "wb");
    
            unsigned long fileSize = sh.iDataSize;
            while (fileSize > 0)
            {
                char buffer[sh.iBlockSize];
                bytes = ::recv (socket, buffer, sh.iBlockSize, 0);
                fwrite (buffer, bytes, 1, pFile);
                fileSize -= bytes;
            }
    
            fclose (pFile);
    

    sh.iBlockSize ist nen Integer aus dem Header den ich vorher schicke und enthält die Größe der Pakete, sh.iDataSize ist die übermittelte Dateigröße.

    Danke schonmal im Voraus.



  • Du solltest den Rückgabewert von send() beachten und es ggf. in einer Schleife aufrufen, bis alle Daten versandt wurden.
    Oder in anderen Worten: Es ist nicht gesichert, dass tatsächlich der komplette Block mit der Größe iBlockSize mit einem send-Aufruf abgeschickt wird.

    http://msdn.microsoft.com/en-us/library/ms740149%28VS.85%29.aspx
    If no error occurs, send returns the total number of bytes sent, which can be less than the number requested to be sent in the len parameter.



  • Nachtrag:
    Dein eigentliches Problem könnte damit behoben werden, diese Zeile hier zu bearbeiten:

    fread (buffer, fileSize, 0, pFile); // Hier muss natürlich 1 statt 0 stehen.
    

    Es würde glaube ich auch Sinn ergeben fread(buffer, 1, fileSize, pFile) zu schreiben, also die beiden Parameter zu tauschen, da er dann alles am Stück lesen kann, während er sonst nur Byte für Byte liest. Kommt aber wohl auch auf die Implementierung von fread an.



  • neonew schrieb:

    Es ist nicht gesichert, dass tatsächlich der komplette Block mit der Größe iBlockSize mit einem send-Aufruf abgeschickt wird.

    Das gilt aber nur für:

    Zitat aus Deinem Link:
    "On nonblocking stream oriented sockets, the number of bytes written can be between 1 and the requested length"

    Bei Nutzung von blockierenden Sockets sendet send "Alles oder Nichts" - das wurde hier auch schon hin und wieder erörtert.



  • Der Fehler lag ganz trivial bei fread, 1 natürlich statt 0 ..
    Ich versteh nich wie ich nach 100 mal durchlesen diesen Fehler nich entdeckt habe 😣

    Die Überprüfung, ob alles gesendet wird, kommt noch, wäre aber eine potentielle Fehlerquelle erstmal mehr gewesen, deshalb hab ichs noch weggelassen .. Wobei das sowieso nur Dekoration wird.
    Danke aber auf jeden Fall für den Hinweis.

    Die Doku erklärt das allerdings andersrum, also dass der 2. Parameter die Größe des zu lesenden Blocks und der 3. Parameter die Anzahl der Blöcke angibt:

    size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
    
    Parameters
    ptr
    Pointer to a block of memory with a minimum size of (size*count) bytes.
    size
    Size in bytes of each element to be read.
    count
    Number of elements, each one with a size of size bytes.
    stream
    Pointer to a FILE object that specifies an input stream.
    

    D.h. bei meiner Variante liest er z.B. 1 Block à 4096 Byte und andersrum eben 4096 Blöcke à 1 Byte, oder nicht?

    Danke für die Hilfe schonmal 🙂



  • Stimmt, das mit fread war Quatsch von mir.


Log in to reply