Ik ben met een Client Server verbinding bezig, en gebruik daarvoor FMX en deze Componenten:
IdTCPServer
IdTCPClient
IdThreadComponent
Het versturen van een Tekst heb ik werkend, maar hoe kan ik het beste een bestand versturen ?
Ik ben met een Client Server verbinding bezig, en gebruik daarvoor FMX en deze Componenten:
IdTCPServer
IdTCPClient
IdThreadComponent
Het versturen van een Tekst heb ik werkend, maar hoe kan ik het beste een bestand versturen ?
zal oa afhangen van de grootte van je bestand. Maar in essentie is het natuurlijk gewoon een reeks bytes die je moet versturen. Maar misschien is iets als ftp een beter protocol als je bestanden wilt versturen en zelf wilt knutselen.
Er zijn vele middleware frameworks die dit gewoon voor je regelen. KbmMW is er bv zo een die een fileservice heeft out of the box. KbmMW werkt ook met fmx, inclusief de mobile platforms. Kim is zelf heel actief bezig met projecten op mobile, met gebruik van FMX en kbmMW.
Hierbij de code die ik nu heb, waarmee ik een Tekst kan zenden:
https://www.uploadarchief.net:443/fi...ngst_zijde.zip
https://www.uploadarchief.net:443/fi...zend_zijde.zip
Hoe zou ik deze aan moeten passen om een bestand te kunnen verzenden ?
Ik probeer het zo werkend te krijgen:
Zend Zijde:
Code:procedure TForm1.Button4Click(Sender: TObject); var FileName: string; Strm: TStream; begin FileName := 'C:\=== DATA ===\20190925_155655_001.jpg'; Strm := TFileStream.Create(FileName, fmCreate); try try IdTCPClient1.IOHandler.Write(TStream(Strm), 0, True); finally Strm.Free; end; except //DeleteFile(FileName); raise; //Verhogen end; Memo1.Lines.Add('ok'); end;
Ontvangst Zijde:
Er is connectie tussen de Server en de Client.Code:procedure TForm1.IdTCPServer1Execute(AContext: TIdContext); var Port : Integer; PeerPort : Integer; PeerIP : string; msgFromClient : string; msgToClient : string; Received: String; begin Received := AContext.Connection.IOHandler.ReadLn; if Received = 'stream' then begin AContext.Connection.IOHandler.Write(TStream(AContext.Data), 0, True); end; // ... getting IP address, Port and PeerPort from Client that connected peerIP := AContext.Binding.PeerIP; peerPort := AContext.Binding.PeerPort; end;
Als ik aan de Zend zijde op Button4 klik, dan krijg ik de melding OK, maar er gebeurd niets meer dan dat het bestand ineens leeg is.
Wat doe ik allemaal verkeerd, en hoe geef ik aan de Ontvangst zijde op hoe en waar het te ontvangen Bestand moet worden opgeslagen ?
MMSoft: stop een header voor je stream met daarin o.a. de size in bytes. In de client lees je de header dan, en dan weet je hoeveel bytes aan filedata je kan ontvangen.
Ontvangen is wat lastiger, omdat je niet kan wachten tot alle data binnen is. Je moet iedere zoveel kb (ik doe 32kb) de data uit je socket halen en (tijdelijk of permanent) opslaan, tot je alles binnen hebt.
Waar komt dit voorbeeld vandaan? Ik zie in de verzender .write() staan en in de ontvanger ook. Beide tegelijk schrijven maar de socket lijkt mij niet juist te zijn.
Volgens mij heeft IOHandler ook een .readstream() en .write() (voor stream) waar het met die headers met size al geregeld is. Je moet dan wel de juiste parameters gebruiken.
Zie bv.
https://stackoverflow.com/questions/...nd-idtcpserver
Dit is een mengeling van meerdere voorbeelden (die allemaal anders waren).Waar komt dit voorbeeld vandaan?
Code:procedure TForm1.IdTCPServer1Execute(AContext: TIdContext); var Port : Integer; PeerPort : Integer; PeerIP : string; msgFromClient : string; msgToClient : string; Received: String; ms:TMemoryStream; begin try ms:=TMemoryStream.Create; AContext.Connection.IOHandler.ReadStream(ms); ms.SaveToFile('C:\=== DATA ===\TEST.jpg'); except Memo1.Lines.Add( 'Failed to receive' ); end; end;
Na een Klik op Button4 krijg ik de melding OK, maar bestand '20190925_155655_001.jpg' is daarna weer leeg en er is geen bestand 'TEST.jpg' aangemaakt.Code:procedure TForm1.Button4Click(Sender: TObject); var FileName: string; Strm: TStream; begin FileName := 'C:\=== DATA ===\20190925_155655_001.jpg'; Strm := TFileStream.Create(FileName, fmCreate); try try IdTCPClient1.IOHandler.Write(TStream(Strm), 0, True); finally Strm.Free; end; except //DeleteFile(FileName); raise; //Verhogen end; Memo1.Lines.Add('ok'); end;
Nu heb je in de verzend kant dit staan: TFileStream.Create(FileName, fmCreate)
Met fmCreate maak je een nieuw leeg bestand aan.
Maar aan de verzendkant wil jij dat bestand toch niet vernietigen net voor verzenden?
http://docwiki.embarcadero.com/RADSt...g_File_StreamsfmCreate
Create a file with the given name. If a file with the given name exists, open the file in write mode.
Logisch dus dat het bestand aan de verzendkant dus leeg raakt en er geen bestand ontvangen wordt.
En AContext.Connection.IOHandler.ReadStream(ms); lees het aantal bytes dat in de komende "readtimeout" ms op de socket beschikbaar is. Het leest niet gegarandeerd het hele bestand.
Readstream kon dacht ik wel de streamsize inlezen als header. Die moet dan wel meegegeven worden (wat iohandler.write standaard niet doet. Er moet dus ook echt goed maar de parameters gekeken worden. Dus wel of geen header meesturen.
https://forum.lazarus.freepascal.org...1522#msg291522By default, TIdIOHandler.Write(TStream) DOES NOT send the stream size, but TIdIOHandler.ReadStream() DOES expect a size to be sent. This is one of the rare cases where a pair of write/read methods do not compliment each other.
Wel voor Lazarus maar Indy zal daar niet zo verschillend zijn. Er staan daar wat juiste combinaties.
Maar goed... de stackoverflow link die ik gaf had ook al een werkend voorbeeld (met verzenden van size).
Ik heb nu dit, en het bestand wordt niet meer gewist:
Code:procedure TForm1.Button4Click(Sender: TObject); var FileName: string; Strm: TStream; begin FileName := 'C:\=== DATA ===\20190925_155655_001.jpg'; Strm := TFileStream.Create(FileName, fmOpenWrite); try try IdTCPClient1.IOHandler.Write(TStream(Strm), 0, True); finally Strm.Free; end; except //DeleteFile(FileName); //raise; //Verhogen Memo1.Lines.Add('Ok 1'); end; end;
Het valt mij nu pas op dat de verbinding meteen verbroken wordt als ik deze opstart, dus nog voordat ik iets verzend.
Ik gebruik de code zoals in de Zip's, en heb alleen de bovengenoemde wijzigingen erin geplaatst.
In het begin waarbij ik alleen een String verzond, had ik dit probleem niet.
Dit krijg ik te zien in de Server:
12:54: Ontvanger Gestart
12:54: Client Connected
12:54: >Port: 20010
12:54: >PeerIP: 192.168.178.32
12:54: >PeerPort: 56104
12:54: Client Disconnected
12:54: >Port: 20010
12:54: >PeerIP: 192.168.178.32
12:54: >PeerPort: 56104
Last edited by MMSoft; 10-Jul-21 at 20:33.
Ik heb het even nagelopen, omdat ik die functie ook gebruik, er zit wat code in die de size automatisch leest.
Dus ik gebruik readstream(strm,<een getal bepaald uit mijn header, bytes available on socket, max 32kb>,false);
en de automatische size read is readstream(strm,-1,false);
Brrr. Mijnenveld.
Delphi Code:
procedure TIdIOHandler.ReadStream(AStream: TStream; AByteCount: TIdStreamSize; AReadUntilDisconnect: Boolean); const cSizeUnknown = -1; begin if (AByteCount = cSizeUnknown) and (not AReadUntilDisconnect) then begin // Read size from connection
Weet iemand hoe je aan oude embarcadero forum posts kan komen? Die link in die SO is ook al weer dood.
Er waren volgens mij wel wat pogingen gedaan om het te archiveren maar geen die echt van de grond gekomen is (of nog in de lucht is).
Voor de >32kb is volgens mij de LargeStream boolean.
@MMSoft Welke vorm wil je nu gebruiken? Als je 0, true gebruikt in write zoals nu dan moet je het ook bij de ontvangstkant goed ontvangen. Wat heb je daar nu staan? Welke van de twee opties uit deze link hem je nu gebruikt? https://forum.lazarus.freepascal.org...html#msg291522
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks