Wie wird ein Buffer bei Socket-Bild-Transfer richtig verwendet ?
-
ich glaube das Problem ist, das ich per "delete mem" im OnRead Event immer wieder meinen Stream lösche...
--> wie kann ich das verhindern ?
Den Stream global deklarieren ?
oder einfach nicht löschen ???ich hoffe auf eure Hilfe
-
Deklaiere den mal global und lösche den erst später weg - ich lösche im FormClose event und deklaiere global.
J0
-
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.
mitint 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 mitint 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.
mitClientSocket1->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, dasif (mem->Size == (img_size + 4))
nie wahr wird...
durhc einShowMessage(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 Versuchhier 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; }