Wie wird ein Buffer bei Socket-Bild-Transfer richtig verwendet ?



  • mmh, so funktioniert's...
    - aber wie kann ich das mit nur einem Button-Click realisieren ?
    - geht das auch irgendwie ohne globale Variablen ?

    nochmals danke für die Hilfe 👍

    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #pragma hdrstop
    
    #include "Unit1.h"
    #include "Jpeg.hpp"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    TMemoryStream *mem=new TMemoryStream();
    
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      TJPEGImage *jpg= new TJPEGImage();
      TMemoryStream *mem=new TMemoryStream();
    
      jpg->LoadFromFile(".\\marikobild.jpg");
      mem->SetSize(0);
      mem->Clear();
      jpg->SaveToStream(mem);
      mem->Position = 0;
      ClientSocket1->Socket->SendStream(mem);
    
      delete jpg,mem;
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
          TCustomWinSocket *Socket)
    {
      //ShowMessage(mem->Size);
      int bufsize = Socket->ReceiveLength();
      BYTE *Buffer = new BYTE[bufsize];
    
      mem->Position=mem->Size;
      Socket->ReceiveBuf(Buffer, bufsize);
      mem->Write(Buffer, bufsize);
    
      delete [] Buffer;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
         TJPEGImage *jpg= new TJPEGImage();
    
         mem->Position=0;
         jpg->LoadFromStream(mem);
         Image2->Picture->Assign(jpg);
    
         delete jpg,mem;
    }
    //---------------------------------------------------------------------------
    


  • huch, warum war ich denn plötzlich ausgeloggt 😮



  • Anonymous schrieb:

    - geht das auch irgendwie ohne globale Variablen ?

    Da du den Stream hier nur innerhalb des Formulars brauchst, macht es sinn, die Variable im Protected-Bereich des Formulars zu deklarieren und im Konstruktor zu intialisieren und im Destruktor zu zerstören.

    -junix



  • ok, ich habe nun folgendes geändert

    in der Unit1.h

    private:	// Anwender-Deklarationen
            TMemoryStream *mem;
    

    im Konstruktor

    __fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
    {
    mem=new TMemoryStream();
    }
    

    und dann noch

    void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
    {
    delete mem;
    }
    

    jetzt habe ich noch das Problem mit dem 2ten ButtonClick --> muss ich sicher ein Protokol oder so definieren ? (nur wie geht das) 😞

    bei meinen Versuchen hat sich noch gezeigt, das die Buffergrösse entscheidend ist für die erfolgreiche Übertragung.
    mit

    int bufsize = Socket->ReceiveLength();
    

    funktioniert es zwar, aber das Bild hat Farbfehler...

    bei anderen Buffergrössen erhalte ich wieder den JPEG-Fehler #50.

    --> wie kann ich das optimieren ?



  • ich hab die größe bei mir auf 1024, so bekomme ich nie fehler bei akzeptabler geschwindigkeit. wenn du es komplett fehlerfrei haben möchtest musst du den wert 1 benutzen, was jedoch langsamer ist.

    Musst einfach mal was ausprobieren, ich finde 1024 optimal.

    J0



  • simonch schrieb:

    jetzt habe ich noch das Problem mit dem 2ten ButtonClick --> muss ich sicher ein Protokol oder so definieren ? (nur wie geht das) 😞

    Ich hab den Entpsrechenden Beitrag aus dem velinkten Thread losgekoppelt und in die FAQ geschoben. Schau da mal im Abschnitt "Netzwerk" nach.

    -junix



  • @junix
    du hast zwar sehr gut die Theorie beschrieben, aber wie ich nun meine Dateigrösse vorne an den Stream dranhänge und dann auf der anderen Seite herausfiltere, ist mir noch nicht ganz klar. 😕

    @J0
    bei einer Buffergrösse von 1 ist das Bild zuerst ganz verschwommen und wenn ich das dann nochmal aus dem Stream lese (durch Button2-Click) ohne Fehler...
    bei 1024 erhalte ich JPEG-Fehler #50.
    ...das verschwommene Bild habe ich mit

    int bufsize = 8;
    

    wegbekommen (seltsam) 😮

    Ohje, ich hoffe meine Fragen gehen euch nicht auf die Nerven, aber ohne euch wüsste ich einfach nicht weiter 😞



  • simonch schrieb:

    @junix
    du hast zwar sehr gut die Theorie beschrieben, aber wie ich nun meine Dateigrösse vorne an den Stream dranhänge und dann auf der anderen Seite herausfiltere, ist mir noch nicht ganz klar. 😕

    Ich hasse es zwar mich selber zu zitieren... aber (von der 1. Seite)

    junix schrieb:

    In dem du, bevor du die Daten aus dem Stream verschickst, zunächst die Länge des BIldes verschickst.

    Beim Empfangen das Selbe in umgekehrter Reihenfolge: Bevor du die Daten in den Stream einliest, liest du schön byte für byte in eine andere Variable.[...]

    Vielleicht noch ergänzend: Man kann mit den SendBuf und ReceiveBuf-Funktionen nicht nur Streams versenden (o;

    Wenn du mir präziser sagen würdest, was du nicht verstehst, dann könnte ich dir auch genauer helfen (o;

    -junix



  • simonch schrieb:

    wenn ich das dann nochmal aus dem Stream lese (durch Button2-Click) ohne Fehler...

    kannst du mal den button2-code zeigen? und den dazu passenden code der vorher ausgeführt wird? (du meintest ja, dass du nochmal aus dem stream liest - mit dem selben code?)

    J0



  • der Button2-Code..

    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
         TJPEGImage *jpg= new TJPEGImage();
         mem->Position=0;
         jpg->LoadFromStream(mem);
         Image2->Picture->Assign(jpg);
         delete jpg,mem;
    }
    

    davor wird mehrfach das OnRead-Event ausgeführt

    void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
          TCustomWinSocket *Socket)
    {
      //ShowMessage(mem->Size);
      int bufsize = 8;//Socket->ReceiveLength();
      BYTE *Buffer = new BYTE[bufsize];
    
      mem->Position=mem->Size;
      Socket->ReceiveBuf(Buffer, bufsize);
      mem->Write(Buffer, bufsize);
    
      delete [] Buffer;
    }
    


  • @junix
    "Wenn du mir präziser sagen würdest, was du nicht verstehst, dann könnte ich dir auch genauer helfen "
    --> ich weiss nicht, wie ich die Grösse des Bildes an meinen Stream dranhänge,d.h.
    mit

    ClientSocket1->Socket->SendBuf(memsend->Memory,memsend->Size);
    

    übertrage ich ja den Stream, nur

    ClientSocket1->Socket->SendBuf(memsend->Size+":"+memsend->Memory,memsend->Size+memsend->Size.Length+1);
    

    ist wohl unmöglich 😃

    weiterhin weiss ich nicht, wie ich meine Bildgrösse am Server rausfiltere ?
    --> damit ich byteweise die Zahlen ermitteln kann, muss ich meinen Buffer wohl auf 1 setzen, was dann wiederum Problem mit den Bilddaten im Stream bringt.
    Ist es vielleicht möglich dann erst bis zum : zu lesen, und dann nachträglich die bufsize zu verändern (bei mir halt halt auf 😎
    Aber wie kann ich auf die einzelnen Zeichen zugreifen und auf ein : überprüfen ?

    Fragen über Fragen 😮



  • Hier mal ein Simpelst-"Protokoll", ausgehend von deinem Beispielcode:

    //--------------------------------------------------------------------------- 
    
    #include <vcl.h>
    #pragma hdrstop 
    
    #include "Unit1.h"
    #include "Jpeg.hpp" 
    //---------------------------------------------------------------------------
    #pragma package(smart_init) 
    #pragma resource "*.dfm"
    TForm1 *Form1; 
    TMemoryStream *mem=new TMemoryStream();
    
    int img_size = 0; // speichert die Grösse der zu übertragenden Daten
    
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner) 
            : TForm(Owner)
    { 
    }
    //--------------------------------------------------------------------------- 
    
    void __fastcall TForm1::Button1Click(TObject *Sender) 
    {
      TJPEGImage *jpg= new TJPEGImage();
      TMemoryStream *mem=new TMemoryStream();
    
      jpg->LoadFromFile("c:\\terminal1.jpg");
      jpg->SaveToStream(mem);
    
      // Grösse der zu übertragenden Daten ermitteln
      img_size = mem->Size;
    
      // Inhalt der ersten 4 Bytes des Streams am Ende anfügen (Integer -> 4 Byte, besser wäre sizeof(int) ;))
      char ch[5];
      mem->Seek(0, 0);
      mem->Read(ch, 4);
      mem->Seek(0, 2);
      mem->Write(ch, 4);
    
      // img_size in den ersten 4 Bytes des Streams speichern, der "Header"
      mem->Seek(0, 0);
      mem->Write(&img_size, 4);
    
      img_size = 0; // zurücksetzen
    
      mem->Seek(0, 0); 
      ClientSocket1->Socket->SendStream(mem);
    
      delete jpg;
      delete mem;
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
          TCustomWinSocket *Socket)
    {
      int bufsize = Socket->ReceiveLength();
      BYTE *Buffer = new BYTE[bufsize];
    
      mem->Seek(0, 2);
      Socket->ReceiveBuf(Buffer, bufsize);
      mem->Write(Buffer, bufsize);
    
      delete [] Buffer;
    
      if (img_size == 0) // erstes Paket ...
      {
        mem->Seek(0, 0);
        mem->Read(&img_size, 4); // .. also Gesamtgrösse auslesen
      }
      else if (mem->Size == (img_size + 4)) // Stream hat Gesamtgrösse + Headergrösse,
        Button2->Click();                   // dh. die Übertragung ist beendet
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
         TJPEGImage *jpg= new TJPEGImage();
    
         char ch[5];
         // letzten 4 Bytes wieder an den Anfang kopieren, sind ja Teil des Bildes
         mem->Seek(-4, 2);
         mem->Read(ch, 4);
         mem->Seek(0, 0);
         mem->Write(ch, 4);
    
         // die zusätzlichen Bytes abschneiden
         mem->Size -= 4;
    
         mem->Seek(0, 0);
         jpg->LoadFromStream(mem);
         Image2->Picture->Assign(jpg);
    
         delete jpg;
         delete mem;
    }
    //---------------------------------------------------------------------------
    

    Leider gibt's bei den Streams ja kein Insert oder Delete, deshalb muss man ein bischen hin- und herkopieren.



  • hallo Jansen,

    vielen Dank für dein Beispiel 🙂

    ...du wirst es nicht glauben, aber bei mir passiert garnix, wenn ich auf's Knöpfchen (Button1) drücke ???

    hier der nach deinen Vorgaben umgebaute Code, vielleicht weisst du ja woran das liegt ?

    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #pragma hdrstop
    
    #include "Unit1.h" 
    #include "Jpeg.hpp"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    TMemoryStream *mem=new TMemoryStream();
    int img_size=0;
    
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      TJPEGImage *jpgsend= new TJPEGImage();
      TMemoryStream *memsend=new TMemoryStream();
    
      jpgsend->LoadFromFile(".\\marikobild.jpg");
      jpgsend->SaveToStream(memsend);
    
      img_size = memsend->Size;
    
      char ch[5];
      memsend->Seek(0, soFromBeginning);
      memsend->Read(ch, 4);
      memsend->Seek(0, soFromEnd);
      memsend->Write(ch, 4);
    
      memsend->Seek(0, soFromBeginning);
      memsend->Write(&img_size, 4);
    
      img_size = 0;
    
      memsend->Seek(0, soFromBeginning);
      ClientSocket1->Socket->SendBuf(memsend->Memory,memsend->Size);
    
      delete jpgsend;
      delete memsend;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
          TCustomWinSocket *Socket)
    {
      int bufsize = Socket->ReceiveLength();
      BYTE *Buffer = new BYTE[bufsize];
    
      mem->Seek(0, soFromEnd);
      Socket->ReceiveBuf(Buffer, bufsize);
      mem->Write(Buffer, bufsize);
      delete [] Buffer;
    
      if (img_size == 0)
      {
        mem->Seek(0, soFromBeginning);
        mem->Read(&img_size, 4);
      }
      else if (mem->Size == (img_size + 4))
      {
         TJPEGImage *jpg= new TJPEGImage();
    
         char ch[5];
         mem->Seek(-4, soFromEnd);
         mem->Read(ch, 4);
         mem->Seek(0, soFromBeginning);
         mem->Write(ch, 4);
    
         mem->Size -= 4;
    
         mem->Seek(0, soFromBeginning);
         jpg->LoadFromStream(mem);
         Image1->Picture->Assign(jpg);
    
         delete jpg;
         delete mem;
      }
    }
    //---------------------------------------------------------------------------
    


  • Tja, hier funktioniert dein Code einwandfrei. 🙂
    Bist du schon mal durchgesteppt? Wird zB. am Anfang das Bild überhaupt geladen, wird die img_size richtig geschrieben und ausgelesen oder wird die "else if"-Abfrage jemals wahr?



  • es hängt an der else-if Abfrage...
    wenn ich nach dem abholen der img_size
    ein ShowMessage(mem->Size);
    setze, wird in 8192er Schritten runtergezählt???

    if (img_size == 0)
      {
        mem->Seek(0, soFromBeginning);
        mem->Read(&img_size, 4);
      }
      ShowMessage(mem->Size);
    

    😕



  • ich habe jetzt fast die ganze Nacht an diesem blöden Problem gesessen 😞
    --> so langsam verzweifele ich, könnt ihr mir vielleicht noch einmal weiterhelfen ?

    - das laden des Bildes (auf ClientSeite) funktioniert
    - die Dateigrösse wird auch richtig übergeben
    -> das Problem ist, das

    if (mem->Size == (img_size + 4))
    

    nie wahr wird...
    durhc ein

    ShowMessage(mem->Size);
    

    habe ich gesehen, das seltsamerweise die Streamgrösse kleiner wird, könnt ihr mir das erklären ? 😕

    int img_size=0;
    TMemoryStream *mem=new TMemoryStream();
    
    void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
          TCustomWinSocket *Socket)
    {
      int bufsize = Socket->ReceiveLength();
      BYTE *Buffer = new BYTE[bufsize];
    
      mem->Seek(0, soFromEnd);
      Socket->ReceiveBuf(Buffer, bufsize);
      mem->Write(Buffer, bufsize);
      delete [] Buffer;
    
      ShowMessage(mem->Size);
      if (img_size == 0)
      {
        mem->Seek(0, soFromBeginning);
        mem->Read(&img_size, 4);
      }
    
      if (mem->Size == (img_size + 4))
      {
         TJPEGImage *jpg= new TJPEGImage();
    
         char ch[5];
         mem->Seek(-4, soFromEnd);
         mem->Read(ch, 4);
         mem->Seek(0, soFromBeginning);
         mem->Write(ch, 4);
    
         mem->Size -= 4;
    
         mem->Seek(0, soFromBeginning);
         jpg->LoadFromStream(mem);
         Image1->Picture->Assign(jpg);
    
         delete jpg;
         delete mem;
      }
    }
    


  • Hi,
    vielleich wird die esle if
    nie war weil die img_size keine daten von dem Stream bekommt.

    if (img_size == 0)
      {
        Stream->Seek(0, 0);
        Stream->Read(&img_size, 4);
      }
      ShowMessage(img_size); // <-- img_size ist bei mir immer 0 ? o_O ?
    


  • leider nein, bei mir steht in img_size die Grösse des Bildes...
    --> trotzdem danke für den Versuch 🙂

    hier nochmal der ClientCode

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      TJPEGImage *jpgsend= new TJPEGImage();
      TMemoryStream *memsend=new TMemoryStream();
    
      jpgsend->LoadFromFile(".\\testbild.jpg");
      jpgsend->SaveToStream(memsend);
    
      img_size = memsend->Size;
    
      char ch[5];
      memsend->Seek(0, soFromBeginning);
      memsend->Read(ch, 4);
      memsend->Seek(0, soFromEnd);
      memsend->Write(ch, 4);
    
      memsend->Seek(0, soFromBeginning);
      memsend->Write(&img_size, 4);
      img_size = 0;
    
      memsend->Seek(0, soFromBeginning);
      ClientSocket1->Socket->SendBuf(memsend->Memory,memsend->Size);
    
      delete jpgsend;
      delete memsend;
    }
    


  • Ich denke, das hatte gestern schon funktioniert (vor dem Editieren deiner Nachricht ;))?

    Nach dem Abarbeiten diese Abschnittes

    mem->Seek(0, soFromEnd); 
      Socket->ReceiveBuf(Buffer, bufsize); 
      mem->Write(Buffer, bufsize);
    

    ist der Stream kleiner als zu Beginn des Abschnittes?
    Schwer zu glauben, insbesondere, da die Streamgrösse dann ja schon nach dem ersten Lesen kleiner als Null sein müsste.



  • schwer zu glauben aber wahr...
    versuche mal den Abschnitt so auszuführen.

    mem->Seek(0, soFromEnd);
      Socket->ReceiveBuf(Buffer, bufsize);
      mem->Write(Buffer, bufsize);
      delete [] Buffer;
    
      ShowMessage(mem->Size);
    

    dann erhalte ich eine immer kleiner werdende mem->size ???

    p.s.
    ich hatte gestern meinen Eintrag editiert, da ich zum Test ob das laden auf Clientseite funktioniert ein zweites TImage angelegt hatte und in meinem Übereifer gedacht hatte, es wäre das erste *schäm* 😃


Anmelden zum Antworten