Protokollentwicklung



  • Was willst du denn mit dem "if (mem)" da noch?

    Ausserdem würde ich nochmal genau überlegen, ob ReceiveBuf() wirklich immer die ganze Buffersize empfängt oder nicht. Als kleiner Tip: Es muss einen Grund geben, wieso ReceiveBuf() das zurückliefert was es zurückliefert (o;

    Ansonsten ist das Verhalten aber völlig logisch... Denk nochmal genau darüber nach.

    -junix



  • Jaaaaa Junix mein Freund, pro Aufruf subtrahiere ich 1024 byte von filesize solange bis nur noch ein Rest kleiner 1024 bleibt und dies die letzte Puffergröße ist 😮

    <= Held vom Erdbeerfeld 😃



  • Heisst das jetzt, dein Problem ist gelöst?

    Übrigens: Ich persönlich fänds erheblich eleganter den Rückgabewert von ReceiveBuf() auszuwerten. Es verringert die Dateifehler (o;

    -junix

    [edit]Ausserdem kümmer dich mal um ordentliche Kommentare und wichtiger: Anständige und aussagekräftige Variablennamen!!![/edit]



  • Das habe ich schon gemacht. Muss zum Fliegerarzt und melde mich später wieder !



  • Ich habe das senden und empfangen so weit hin gekriegt. Zuerst kommuniziert der Client etwas mit dem Server, es wird mitgeteilt, ob Daten gesendent werden sollen, dann die Grösse der Datei und wenn der User dies empfangen möchte, wird dann der Stream gesendet. Ich habe zusätzlich noch ein Form angelegt, welches den Status der Übermittlung anzeiget, Totale Anzahl zusendender Bytes, Anzahl der gesendeten Bytes und einem TCGauge als Frotschrittsanzeige. Das Problem ist jetzt, dass ich ja ein

    Application->ProcessMessages();
    

    benötige, um das Label mit den empfangenen Bytes zu aktualisieren. Blos wenn ich das drin habe, erhalte die Fehlermeldung: Zugriffsverletzung bei Adresse blablabla. Lesen von Adresse blablabla. lass ich es weg geht alles gut. Wieso? 😕
    Hier mal der Code:

    BytesReceive = Socket->ReceiveBuf(Buffer, BufferSize); //Buffer auslesen
          Stream->Write(Buffer, BytesReceive);                      //Buffer in Stream schreiben
          TotalBytesReceived += BytesReceive;                       //Anzahl empfangene Bytes aufsummieren
          Progress->TransferStatus->Progress = TotalBytesReceived;
          Progress->SendBytesLabel->Caption = TotalBytesReceived;
          //Application->ProcessMessages();
          if(TotalBytesReceived == TotalBytes)
          {
             free(Buffer);                                   //Speicherbereich wieder frei geben
             Progress->Close();                              //Statusfenster schliessen
             Stream->Seek(0, soFromBeginning);               //Stream auf Anfang setzten
             Stream->SaveToFile(SaveDialog1->FileName);      //Stream abspeichern
             Stream -> Clear();                              //Speicher freigeben
             delete Stream;                                  //Stream frei geben
             delete [] Buffer;                               //Buffer frei geben
             FileReadyToReceive = false;
             FileSizeReadyToReceive = false;
             FileSizeReceive = false;
             ServerSocket1->Close();
          }
    


  • Hab deine Variante in ne Testversion eingebaut und muss feststellen das der MemoryStream beim senden sowas von lahm ist. Wird der Stream byte für byte versendet :p ?
    ProcessMessages verwendet man in Schleifen, wie es bei events aussieht weiß ich leider noch nicht. Komisch ist das der Empfänger abraucht wenn ich das 2. mal senden möchte. Der erste File Transfer klappt super aber lahm. Bisher hat der Filestream am besten Funktioniert auch wenn er mir 80 -100 % CPU Last für den Process beansprucht.

    @wedmer: Ich kann ab Sonntag Abend wieder Mitarbeiten wenn ich vom Flugplatz zurück bin. Das bekommen wir schon hin 🤡

    @Junix: Vielen Dank für deine unermüdliche Hilfe, ich bereite das OnReceive auf und Poste es am Sonntag 😉



  • wedmer schrieb:

    [...]
             free(Buffer);                                   //Speicherbereich wieder frei geben
    [...]
             delete [] Buffer;                               //Buffer frei geben
          }
    

    Was soll das denn werden?

    Wenn new [] dann ist free bestimmt nicht gefragt.

    Kleiner Tip am Rande. Wenn delete ausgeführt wird, dem Zeiger gleich NULL zuweisen. Das führt dazu, das man doppelte Löschungen besser findet (AV auf Adresse 0 ist eindeutiger zu identifizieren.)



  • Ups,
    dass free(Buffer) kam daher, dass ich zuerst den Buffer mit malloc erstellt habe und als ich dann auf new gewechselt habe. Habe jetzt nach jedem delete ein =NULL eigesetzt. Jetzt erhalte ich aber immer noch eine Information, mit dem Inhalt Zugriffsverletzung auf eine Adresse ≠0x00000000 liegt das daran, dass Application->ProcessMessages(); nicht bei Events verwendet werden darf, da es ja eigentlich für Schleifen gedacht ist?

    @Zero01: habe nun meine MemoryStreams in FileStreams umgewandelt, kann bei mir aber bei der Geschwindigkeit keine Unterschied feststellen.



  • Hat damit gar nichts zu tun. Wo genau passiert denn die AccessVoilation?

    Jedenfalls ist das alles jetzt ein Indiz dafür, dass du irgendwo Speicher zerstörst, auf den du in einem späteren Event wieder zugreifen würdest.



  • Wo genau weiss ich auch nicht, er zeigt mir im CPU-Fenster auf den Befehl:
    7C91EDDC push ebx
    Wo dies im Code genau ist, weiss ich auch nicht. Es muss von mir aus gesehen im OnClientRead-Event sein die Meldung tritt erst ein, nach dem bereits einig Bytes Übertragen wurden.
    komisch ist, dass die Meldung nur kommt, wenn ich die ProcessMessages() drin lasse, nehme ich die raus geht alles prima.



  • Scroll mal im CPU-Fenster hoch bis zur nächsten dir bekannten Zeile in C. Alternativ schliesse das CPU-Fenster und du solltest in der IDE die passende Zeile markiert kriegen.

    Wenn das auch nichts hilft, dann findest du irgendwo in den Debugfenstern (Ich gluab View-> Debug) den sogenannten "Callstack" oder "Aufrufstack" da wird dir angezeigt in welcher Funktion du grade steckst und wie du da hingelangt bist (aufrufende Funktionen)



  • junix schrieb:

    Scroll mal im CPU-Fenster hoch bis zur nächsten dir bekannten Zeile in C.

    Wie meinst du das? Bei mir stehen im CPU-Fenster nur Assembler befehle.
    Habe jetzt mal das mit dem Aufruf-Stack gemacht, da steht bei mir: ntdll.dll 😕



  • Es kann doch sein, dass die VCL intern mit WSAAsyncSelect() arbeitet. Dann wird beim Eintreffen von Daten eine Message an die Form gesendet. D.h., er geht wieder in OnReceive rein. Eine feine Rekursion, die möglicherweise den Fehler verursacht...
    So kannst du einfach prüfen, ob meine Vermutung tatsächlich der Fall ist:

    void __fastcall TForm1::OnReceiveData(TObject* Sender)  // Oder was weiß ich, wie die Rotine bei dir heißt...
    {
       static bool IsProcessMessagesOn = false;
    
       if( !IsProcessMessagesOn )
       {
          BytesReceive = Socket->ReceiveBuf(Buffer, BufferSize); //Buffer auslesen 
          Stream->Write(Buffer, BytesReceive);                      //Buffer in Stream schreiben 
          TotalBytesReceived += BytesReceive;                       //Anzahl empfangene Bytes aufsummieren 
          Progress->TransferStatus->Progress = TotalBytesReceived; 
          Progress->SendBytesLabel->Caption = TotalBytesReceived; 
    
          IsProcessMessagesOn = true;
          Application->ProcessMessages(); 
          IsProcessMessagesOn = false;
    
          if(TotalBytesReceived == TotalBytes) 
          { 
             free(Buffer);                                   //Speicherbereich wieder frei geben 
             Progress->Close();                              //Statusfenster schliessen 
             Stream->Seek(0, soFromBeginning);               //Stream auf Anfang setzten 
             Stream->SaveToFile(SaveDialog1->FileName);      //Stream abspeichern 
             Stream -> Clear();                              //Speicher freigeben 
             delete Stream;                                  //Stream frei geben 
             delete [] Buffer;                               //Buffer frei geben 
             FileReadyToReceive = false; 
             FileSizeReadyToReceive = false; 
             FileSizeReceive = false; 
             ServerSocket1->Close(); 
          }
       }
    }
    

    So könnte es zwar sein, dass nicht alles durchkommt, aber du wirst merken, ob du wieder eine AccessViolation bekommst oder nicht. Ich würde dir eh dazu raten, die ganze daten-Empfangs-Routine in einen eigenen Thread zu packen.



  • Super Tip danke, genau da lag der Fehler.👍 Dann werde ich einfach die Anzeige der empfangenen Bytes weglassen, das TCGauge genügt ja auch.



  • Bei mir funzt es mittlerweile auch schon gut, Perfekt ist es aber noch nicht da Teilweiße die Sendeschleife rausspringt obwohl der File noch gar nicht zu ende gesendet wurde:

    char buf[1024];
     int c,b;
    
     TFileStream *in = new TFileStream(Form1->OpenDialog1->FileName, fmOpenRead);
     in->Seek(0,soFromBeginning);
    
    do
         {
             Application->ProcessMessages();
             b = in->Read(buf,sizeof(buf));
             c = Form1->ClientSocket1->Socket->SendBuf(buf,b);
    
            while(c == -1)
            {
             Application->ProcessMessages();
             b = in->Read(buf,sizeof(buf));
             c = Form1->ClientSocket1->Socket->SendBuf(buf,b);
            }
        }
         while(b == sizeof(buf));
         delete in;
    

    Was mache ich falsch da er manchmal zu früh aufhört zu senden? Beispiel: Von 123456 bytes sendet er dann meistens nur 123453. Wie schaffe ich es das er immer die komplette Datei überträgt ?



  • So, nun hab ich ne einigermaßen stabile Variante ausgetüftelt:

    char buf[1024];
     int c,b,bytecount = 0;
    
         TFileStream *in = new TFileStream(Form1->OpenDialog1->FileName, fmOpenRead);
         in->Seek(0,soFromBeginning);
    
          do
         {
             Application->ProcessMessages();
             b = in->Read(buf,sizeof(buf));
             c = Form1->ClientSocket1->Socket->SendBuf(buf,b);
    
               if (c != -1)
               {
                UploadWindow->ProgressBar1->Position += c;
                bytecount += c;
                UploadWindow->Label7->Caption = String(UploadWindow->ProgressBar1->Position)+ " bytes";
               }
            while(c == -1)
            {
             c = Form1->ClientSocket1->Socket->SendBuf(buf,b);
    
                   if (c != -1)
                 {
                  UploadWindow->ProgressBar1->Position += c;
                  bytecount += c;
                  UploadWindow->Label7->Caption = String(bytecount)+ " bytes";
                 }
            }
        }
         while(File_Size > bytecount && b == sizeof(buf));
         delete in;
    

    Sieht jemand von euch Fehler 😕 mehrere Files sendet er problemlos aber bei einigen Bricht er ziemlich am Ende des Files die do-while Schleife ab



  • Hab den Fehler gefunden ! Jetzt läufts wie geschmiert



  • @Zero01 währe nett wenn du den fehlerfreien Code auch Posten könntest!

    Bin nämlich auch gerade Dabei so einen File Transfer zu schreiben.

    danke

    gruß



  • UNd was genau bereitet dir Probleme?

    Oder war "schreiben" nur ein Tippfehler und du wolltest "kopieren" schreiben? (-;



  • void SendFile(String file_path,String ip_address,int File_Size)
    {
     char buf[1024];
     int c,b,bytecount = 0;
    
     int limiter = file_path.LastDelimiter("\\");
     int stringlenght = file_path.Length() - limiter;
     String Filename = file_path.SubString(limiter + 1,stringlenght);
    
     UploadWindow = new TForm3(Form1);
     if(UploadWindow)
       {
          UploadWindow->ClientSocket1->Address = ip_address;
          UploadWindow->ClientSocket1->Open();
          UploadWindow->Caption = "File Transfer ";
          UploadWindow->Label4->Caption = "Uploading...";
          UploadWindow->Label6->Caption = IntToStr(File_Size);
          UploadWindow->Label8->Caption = file_path;
          UploadWindow->ProgressBar1->Position = 0;
          UploadWindow->ProgressBar1->Min = 0;
    
          if (File_Size > 0)
          UploadWindow->ProgressBar1->Max = File_Size;
    
          UploadWindow->Label3->Caption = Filename;
          UploadWindow->Show();
          UploadWindow->in->Seek(0,soFromBeginning); //-- in ist der FileStream
          do
         {
             Application->ProcessMessages();
             b = UploadWindow->in->Read(buf,sizeof(buf));
    
             if(UploadWindow->ClientSocket1->Socket->Connected)
             c = UploadWindow->ClientSocket1->Socket->SendBuf(buf,b);
    
               if (c != -1)
               {
                UploadWindow->ProgressBar1->Position += c;
                bytecount += c;
                UploadWindow->Label7->Caption = String(UploadWindow->ProgressBar1->Position)+ " bytes";
               }
            while(c == -1 && UploadWindow->ClientSocket1->Socket->Connected)
            {
             Application->ProcessMessages();
    
             if(UploadWindow->ClientSocket1->Socket->Connected)
             c = UploadWindow->ClientSocket1->Socket->SendBuf(buf,b);
    
                   if (c != -1)
                 {
                  UploadWindow->ProgressBar1->Position += c;
                  bytecount += c;
                  UploadWindow->Label7->Caption = String(bytecount)+ " bytes";
                 }
            }
        }
         while(b == sizeof(buf) && UploadWindow->ClientSocket1->Socket->Connected);
    
         if (IntToStr(bytecount) == IntToStr(File_Size))
         UploadWindow->Close();
         else
         {
          if(UploadWindow->Label4->Caption != "Socket Error !")
          UploadWindow->Label4->Caption = "Stream corrupt, size dismatch";
         }
    
      }
     }
    

    Versuchs mal bei dir. Wäre nett wenn wir über die Fehler diskutieren könnten 👍


Anmelden zum Antworten