Dateien über Winsock versenden



  • Moin!
    Ich versuche gerade, eine Datei über Winsock zu versenden - doch irgednwie
    klappt das nicht so, wie ich mir das vorstelle 🙄
    Könnte mir da einer von euch weiterhelfen?

    Vielen Dank im vorrau*s!
    Maxime 🙂

    Der Code:

    //EMPFÄNGER
    
    //Die Buffergröße
    char buffer[256];
    
    while (strcmp(buffer, "") == 0)
    {
    	rc=recv(s,buffer,256,0);
    	buffer[rc]='\0';
    }
    
    Sleep(5000);		
    int FileSize = atoi(buffer);
    
    //Die eigentliche Datei empfangen
    
    	char fbuf[sizeof (FileSize)];
    	rc=recv(s,fbuf,256,0);
    	fbuf[rc]='\0';
    
    	HANDLE sendfile; DWORD BytesWritten = 0;
    	sendfile = CreateFile("text.txt", GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, NULL, NULL);
    	WriteFile(sendfile, fbuf, FileSize, &BytesWritten, NULL);
    
    	CloseHandle(sendfile);
    
    //SENDER
    	HANDLE file;
    	char * buffer;
    	int FileSize = 0;
    	DWORD BytesRead = 0;
    
    	file = CreateFile("text.txt", GENERIC_READ, NULL, NULL, OPEN_EXISTING, NULL, NULL);
    	FileSize = GetFileSize(file, NULL);
    	buffer = new char[FileSize];
    	ReadFile(file, (void*)buffer, FileSize, &BytesRead, NULL);
    
    	char sFileSize[sizeof(FileSize)];
    	sprintf(sFileSize2, "%d\0", FileSize);
    
    	send(connectedSocket, sFileSize2, FileSize, 0);
    	Sleep(250);
    	send(connectedSocket, buffer, FileSize, 0);
    
    	CloseHandle(file);
    


  • Wird denn gar nichts in die Datei geschrieben oder eben nur der Anfang?



  • Es wird leider gar nichts in die Datei geschreiben 😞
    Wenn ich den Buffer selbst bestimme, wird die Datei vollständig übertragen
    - aber das ist ja nicht mein Ziel 😞



  • Also beim Sender ist alles OK - habe gerade einen Test mit ´ner MessageBox gemacht. Nur beim Empfänger wird der Buffer schon falsch empfangen:

    //Sender:
    sprintf(FileSize2, "%d\0", FileSize);
    MessageBox(NULL, FileSize2, NULL, NULL);
    //Dateigröße wird korrekt angezeigt
    
    Empfänger:
    while (strcmp(buffer, "") == 0)
    {
    rc=recv(s,buffer,256,0);
    buffer[rc]='\0';
    }
    
    Sleep(5000);
    MessageBox(NULL, buffer, NULL, NULL);
    //Es sind noch nicht einmal Zahlen zu erkennen
    


  • Klappt es denn, wenn du normalen Text versuchst zu versenden? Und außerdem musst du bedenken, dass Dateien auch mittendrin mal 0-Zeichen haben können - also Vorsicht mit Stringfunktionen 😉



  • Ich denke mal, dass es an den 0-Zeichen liegt.
    Habe den Dateinamen "text.txt" nämlich nur als Beispiel eingesetzt, weil ich
    dachte, an dem Code sei etwas falsch. 🙄 (Eigentlich habe ich vor, eine Gif-Datei zu senden).

    Klappt es denn, wenn du normalen Text versuchst zu versenden?

    Klar! Wenn ich die FileSize ja selber bestimme, wir die Datei vollständig übertragen.

    Das mit den 0-Zeichen wusste ich gar nicht 🙄 - könntest du mir da mal ein paar Alternativen geben?

    Danke 🙂



  • Hat sich erledigt!
    Es hätte

    send(connectedSocket, FileSize2, sizeof(FileSize), 0);
    

    heißen müssen - und nicht

    send(connectedSocket, FileSize2, FileSize, 0);
    


  • char fbuf[sizeof (FileSize)]; 
    rc=recv(s,fbuf,256,0); 
    fbuf[rc]='\0';
    

    dein buffer ist 256 byte gross, so gibt du es auch an
    mit rc erhälst du die bytes, die tasächlich gesendet wurden.

    mein vorschlag, sende ein stream beginnend mit der der anzahl deiner zu senden datei gefolgt mit dem eigendlichen inhalt.

    wenn du die ersten bytes empfängst, z.b size_t == 4 byte weißt du wie gross deine zu empfangende datei ist.

    den buffer würde ich mit 1024 bytes festlegen

    char* rbuf=NULL;
    size_t pos, n;
    
    char fbuf[1024]; 
    rc=recv(s,fbuf,1024,0); 
    if (rbuf==NULL)
    {
      // vorausgesetzt rc>=4 !!
      memcpy(&n, fbuf, sizeof(size_t));
      rbuf=new char[n];
      rc -=sizeof(size_t);
      fbuf +=sizeof(size_t);
    }
    memcpy(rbuf, fbuf, rc);
    pos=rc;
    
    while (n != pos)
    {
      rc=recv(s,fbuf,1024,0);
      memcpy(rbuf, fbuf, rc);
      n +=rc;
    }
    

    so in der richtung würde ich es realisieren

    hat sich ja erledigt



  • Hi vdittrich!
    Vielen Dank für den Code!
    Den kann ich trotzdem gut gebrauchen - denn bei meiner aktuellen
    Lösung werden komischerweise nur die 1. vier Zeichen empfangen 🙄

    Vielen Dank für die ganzen Antworten!



  • Warum werden denn eigetnlich nur die 1. vier Zeichen empfangen?
    Würde mich auch mal interessieren 🙄



  • was etwas schlecht beschrieben

    mein vorschlag, sende ein stream beginnend mit der der grösse (z.b in size_t) zu senden datei gefolgt mit dem eigendlichen inhalt.

    wenn du mindestens die ersten 4 bytes (siehe (z.b in size_t)) empfangen hast, weißt du an hand der im stream gesendeten bytes, wie gross deine datei ist.

    rc=recv(s,fbuf,1024,0);
    // rc enthält die tatsächlich und in deb buffer geschriebenen bytes
    


  • Also... ich versuch´s mal zu verstehen...
    1. Die Variablen werden deklariert. (Klar)
    2. Die Dateigröße und der Dateiinhalt werden in einem Stream empfangen
    3. Wenn rbuf NULL ist, werden die ersten ? Zeichen von fbuf in n "kopiert".
    Den Rest mit - und + versteh´ ich leider noch net 🙄

    Kann ich den Codeteil denn komplett in mein Projekt übernehmen (oder muss ich doch noch etwas verändern)?

    PS: Wie kann ich denn dann mit den neuen Variablen "CreateFile" aufrufen?
    PPS: Kann ich Dateigröße und Dateiinhalt komplett in einem Stream versenden?
    (oder muss ich da noch ein Trennzeichen setzen?)

    Sorry für die vielen Fragen 😞 bin noch ein Newbie 🙄



  • der codeteil muss natürlich noch erweitert werden

    sollte eine gute anleitung sein http://www.c-worker.ch

    das natürlich auch http://zotteljedi.de/doc/socket-tipps.html



  • Hi vdittrich!
    Wollte eigentlich nur wissen, ob ich zwischen der Dateigröße
    und dem Dateiinhalt noch ein Trennzeichen mitsenden muss. 🙄

    Das mit den Sockets verstehe ich ja schon alles 🙂



  • warum trennzeichen?, du weist duch wie gross die bytes sind.
    du baust ein stream auf wie du es möchtest.

    ganz "grass gesehen"

    struct IO
    {
      int  b1;
      UINT b2;
      char s[255];
    };
    IO   io;
    BYTE x[1024];
    memcpy(x, &io, sizeof(IO));   //sende x;
    
    //empfänger
    BYTE y[1024];                 //empfange y
    IO   out;
    
    memcpy(&out, y, sizeof(IO));
    


  • Also wenn ich zum Beispiel den Inhalt "Halloduda" einer Textdatei sende,
    müsste das so aussehen:

    9Halloduda

    Dem Empfänger müsste ich also "sagen", dass das 1. Zeichen die Dateigröße beinhaltet. Daraufhin liest er die nächsten Zeichen und speichert sie in eine Datei.

    Aber die zu sendende Datei ist ja nicht immer gleich groß! Mal 33KB, mal 55KB...
    Woher soll der Empfänger dann wissen, bis wohin der empfangene Stream die Dateigröße beinhaltet - und ab wo der eigentliche Dateiinhalt beginnt?

    Das geht (meiner Meinung nach) nur mit Trennzeichen 😕
    oder liege ich da falsch? 😞



  • du liegst doch schon richtig.

    //stream
    struct STREAM
    {
      size_t nlen;
      char*  str;
    };
    
    STREAM st;
    
    st.str=/*zeiger auf deine dateiinhalt*/
    st.nlen=strlen(st.str);               //oder anders
    
    //dein strem hat nun die gesamte länge st.nlen+sizeof(size_t)
    //abstrakt gesehen
    
    BYTE buf[1024]; 
    
    size_t pos=0; BYTE* b=buf;
    
    memcpy(b, &st.nlen, sizeof(size_t));
    b +=sizeof(size_t);
    
    while (pos != st.nlen)
    {
      size_t n=1024-(b-buf);
      memcpy(b, str+pos, n);
      // send 1024 bytes
      pos +=n; b=buf;
    }
    

    es gibt natürlich noch viele andere wege, z.b ohne buffer
    man muss aufpassen du kannst nur int=INT_MAX zeichen auf einmal senden

    der empfänger sieht vom prinzip gleich aus

    BYTE buf[1024]; size_t pos=0;
    bool blen=false; 
    STREAM st={0,0};
    
    while (blen && pos != st.nlen)
    {
      int n=recv(0, (char*)buf, 1024, 0);
      if (n == SOCKET_ERROR) break;
      char* b=buf;
      if (!blen)
      {
        // etwas übertrieben man hoft ja auf min 4 byte
        int len= pos+n >= sizeof(size_t)? sizeof(size_t)-pos:n;
        memcpy(&st.nlen+pos, buf, len);
        pos +=len;
        blen= pos != sizeof(size_t);
        if (!blen) continue; 
        // jetzt beginnt das char*
        n -=len; b +=len;
        pos=0;
      }
      if (n)
      {
        //in b mit n bytes steht deine teil (stream) datei
        //den du jetzt mit einem offset von pos wieder in deine 
        //datei schreiben kannst
    
        pos +=n;
      }
    }
    

    was besseres viel mir jetzt auch nicht ein



  • Hi vdittrich!
    Sorry, dass ich noch nicht so viel von dem Code verstehe - bin leider noch ein
    (totaler 😕) Newbie. Die Frage ist mir zwar fürchterlich peinlich 😞
    - aber könntest du mir sagen, wie und wo ich send und CreateFile in dem Code benutzen muss; (und ob ich den Code dann komplett in mein Projekt übernehmen kann)?

    Habe leider noch nicht so viel Ahnung von "memcpy" und "size_t" 🙄

    Vielen, vielen Dank im voraus!
    (Diesmal ohne Rächtschraibfähla 🤡)



  • ich denke du solltest dich erst mal mit was einfacheren beschäftigen.

    bei http://zotteljedi.de/doc/socket-tipps.html kannst du dir den kompl. source eines ftp-socket runterladen, das ist doch das was du suchst.

    fertige lösungen wirst du von keinen hier bekommen.



  • Hab ich mir schon gedacht, dass man hier keine fertigen Codes bekommt 🙄

    Es ist doch praktisch möglich, die Datei und die Dateigröße getrennt mit einem | in einem Stream an den Server zu senden.

    Um die Datei und die Dateigröße jeweils in einem String abzuspeichern, kann ich doch dann eine "selbstgeschriebene" 😃 explode - Funktion benutzen:

    std::string explode(char trennzeichen, std::string str, int part)
                       {
                         std::string output;
                          if (part == 0) // Wenn der erste Part gesucht wird
                                         // müssen viele komplizuierte schritte nicht gemacht werden
                             {
                                  string::size_type pos1 = str.find_first_of(trennzeichen);
                                  output = str.substr(0,pos1);
                             }
                             else
                             {
                                 /* Als erstes muss die Anzahl der Trennzeichen in dem
                                    zu Teilendem String festgestellt werden, dies geschieht in
                                    einer Schleife, und wenn die Anzahl (int i) mit (int) part (-1)
                                    übereinstimmt wird die Postition ausfindig gemacht.
                                 */
                                 int s_lengh = strlen(str.c_str());
                                 int match_c = 0;
    
                                 for (int i=0;i<s_lengh;i++)
                                     {
    
                                       if (str[i] == trennzeichen)
                                          {
                                           match_c++;
                                            if (match_c == part)
                                               {
                                                 std::string str_2 = str.substr(i+1, 1000);
                                                 string::size_type pos2 = str_2.find_first_of(trennzeichen);
                                                 output = str_2.substr(0,pos2);
                                               }
                                          }
                                     }
                             }
                         return output;
                       }
    

    ... oder nicht?



  • Wozu so umständlich? Wenn du die Dateigröße direkt als int am Anfang überträgst sind das doch immer 4 Bytes 😉


Anmelden zum Antworten