MrCamarium 0 Posted March 3, 2022 Customer side: procedure TForm1.Button1Click(Sender: TObject); begin try Label1.Caption := 'Connessione in corso...'; client.Port:=2630; client.Host:='127.0.0.1'; client.Connect(); except Label1.Caption := 'Errore Di Connessione'; end; end; procedure TForm1.Button2Click(Sender: TObject); begin client.Disconnect; Label1.Caption := 'Disconnesso'; end; procedure TForm1.Button3Click(Sender: TObject); var TFLFileOut: TFileStream; begin TFLFileOut:= TFileStream.Create(ToDownload.Text, fmOpenRead); Client.IOHandler.Write(TFLFileOut, 0, true); end; procedure TForm1.ClientConnect(Sender: TObject); begin Label1.Caption := 'Connesso'; Button1.Enabled := False; Button2.Enabled := True; end; procedure TForm1.ClientDisconnect(Sender: TObject); begin Label1.Caption := 'Disconnesso'; Button1.Enabled := True; Button2.Enabled := False; end; Server side: procedure TForm1.ServerExecute(AContext: TIdContext); var TFSFileIn: TFileStream; begin Label1.Caption := 'Arriva qualcosa...'; TFSFileIn:= TFileStream.Create(Edit1.Text, fmCreate); AContext.Connection.IOHandler.ReadStream(TFSFileIn); TFSFileIn.Free; end; procedure TForm1.FormCreate(Sender: TObject); begin server.DefaultPort:=2630; server.Active:=true; end; The program compiles correctly but the transferred file is zero. Da Cliente A Server.zip Share this post Link to post
Remy Lebeau 1394 Posted March 3, 2022 (edited) 2 hours ago, MrCamarium said: procedure TForm1.Button3Click(Sender: TObject); var TFLFileOut: TFileStream; begin TFLFileOut:= TFileStream.Create(ToDownload.Text, fmOpenRead); Client.IOHandler.Write(TFLFileOut, 0, true); end; You are leaking the TFileStream object. You need to Free() it when you are done using it. You should wrap the call to Write() in a try..finally block for that, in case Write() raises an exception, eg: procedure TForm1.Button3Click(Sender: TObject); var TFLFileOut: TFileStream; begin TFLFileOut := TFileStream.Create(ToDownload.Text, fmOpenRead or fmShareDenyWrite); try Client.IOHandler.Write(TFLFileOut, 0, true); finally TFLFileOut.Free; end; end; Quote procedure TForm1.ServerExecute(AContext: TIdContext); var TFSFileIn: TFileStream; begin Label1.Caption := 'Arriva qualcosa...'; TFSFileIn:= TFileStream.Create(Edit1.Text, fmCreate); AContext.Connection.IOHandler.ReadStream(TFSFileIn); TFSFileIn.Free; end; Likewise, you should use try..finally here too, to ensure the TFileStream is Free()'d even if an exception is raised. procedure TForm1.ServerExecute(AContext: TIdContext); var TFSFileIn: TFileStream; begin Label1.Caption := 'Arriva qualcosa...'; TFSFileIn := TFileStream.Create(Edit1.Text, fmCreate); try AContext.Connection.IOHandler.ReadStream(TFSFileIn); finally TFSFileIn.Free; end; end; But, more importantly, TIdTCPServer is a multi-threaded component. Its OnExecute event is fired in the context of a worker thread, not the main UI thread. As such, accessing UI controls, such as your TLabel an TEdit controls, is NOT thread-safe. You MUST synchronize with the main UI thread when accessing them, eg: procedure TForm1.ServerExecute(AContext: TIdContext); var FileName: string; TFSFileIn: TFileStream; begin TThread.Synchronize(nil, procedure begin Label1.Caption := 'Arriva qualcosa...'; Filename := Edit1.Text; end end; TFSFileIn := TFileStream.Create(FileName, fmCreate); try AContext.Connection.IOHandler.ReadStream(TFSFileIn); finally TFSFileIn.Free; end; end; Quote The program compiles correctly but the transferred file is zero. Your calls to Write() and ReadStream() are matched up properly, so I cannot see a reason why the received file would be empty, provided that Write() and ReadStream() are actually being called. Did you verify that with your debugger? Edited March 3, 2022 by Remy Lebeau Share this post Link to post
MrCamarium 0 Posted March 4, 2022 Thank you for the answer, The code: procedure TForm1.ServerExecute(AContext: TIdContext); var FileName: string; TFSFileIn: TFileStream; begin TThread.Synchronize(nil, procedure begin Label1.Caption := 'Arriva qualcosa...'; Filename := Edit1.Text; end end; TFSFileIn := TFileStream.Create(FileName, fmCreate); try AContext.Connection.IOHandler.ReadStream(TFSFileIn); finally TFSFileIn.Free; end; end; From errors in the compilation, however, even making the changes you suggested I still have a zero file. I am also attaching the file. 1.zip Share this post Link to post
Remy Lebeau 1394 Posted March 4, 2022 (edited) 9 hours ago, MrCamarium said: The code: ... From errors in the compilation What errors, exactly? Please be more specific. And, are you really using Delphi XE? That is 12 years old. Are you, at least, using an up-to-date version of Indy? Or, are you are using a 12-year-old version? Quote however, even making the changes you suggested I still have a zero file. The code to transfer the file looks fine to me, so you are just going to have to debug deeper. Quote I am also attaching the file. 1.zip That zip file contains the same client code you originally posted. It does not include the changes I suggested for the client. Edited March 4, 2022 by Remy Lebeau Share this post Link to post
qubits 20 Posted March 4, 2022 (edited) 9 hours ago, MrCamarium said: TThread.Synchronize(nil, procedure begin Label1.Caption := 'Arriva qualcosa...'; Filename := Edit1.Text; end end; in above quoted, replace last end with ) that's all i see.. should note, i do believe serverexecute will be called multiple times until all data is received, depending on your file size it may be chopped up into smaller chunks, usually like 1500 byte or so, depends on routers and os configs. Edited March 4, 2022 by qubits Share this post Link to post
MrCamarium 0 Posted March 4, 2022 2 hours ago, Remy Lebeau said: What errors, exactly? Please be more specific. And, are you really using Delphi XE? That is 12 years old. Are you, at least, using an up-to-date version of Indy? Or, are you are using a 12-year-old version? The code to transfer the file looks fine to me, so you are just going to have to debug deeper. That zip file contains the same client code you originally posted. It does not include the changes I suggested for the client. I am using Embarcadero® RAD Studio XE Version 15.0.3890.34076 the version of Indy is 10.5.7 the code: procedure TForm1.ServerExecute(AContext: TIdContext); var FileName: string; TFSFileIn: TFileStream; begin TThread.Synchronize(nil, procedure begin Label1.Caption := 'Arriva qualcosa...'; Filename := Edit1.Text; end end; TFSFileIn := TFileStream.Create(FileName, fmCreate); try AContext.Connection.IOHandler.ReadStream(TFSFileIn); finally TFSFileIn.Free; end; end; Da errore: [DCC Error] Unit1.pas(46): E2029 ')' expected but 'END' found Correcting it like this: procedure TForm1.ServerExecute(AContext: TIdContext); var FileName: string; TFSFileIn: TFileStream; begin TThread.Synchronize(nil, procedure begin Label1.Caption := 'Arriva qualcosa...'; Filename := Edit1.Text; end; end; TFSFileIn := TFileStream.Create(FileName, fmCreate); try AContext.Connection.IOHandler.ReadStream(TFSFileIn); finally TFSFileIn.Free; end; end; It gives me an error: [DCC Error] Unit1.pas(45): E2029 ')' expected but ';' found 1.zip Share this post Link to post
qubits 20 Posted March 4, 2022 (edited) there's an open bracket on Synchronize Should be procedure TForm1.ServerExecute(AContext: TIdContext); var FileName: string; TFSFileIn: TFileStream; begin TThread.Synchronize(nil, procedure begin Label1.Caption := 'Arriva qualcosa...'; Filename := Edit1.Text; end ); TFSFileIn := TFileStream.Create(FileName, fmCreate); try AContext.Connection.IOHandler.ReadStream(TFSFileIn); finally TFSFileIn.Free; end; end; Indy's got nice FTP components, might be easier solution.. Edited March 4, 2022 by qubits Share this post Link to post
Remy Lebeau 1394 Posted March 5, 2022 (edited) 7 hours ago, qubits said: in above quoted, replace last end with ) OK, thanks. Quote should note, i do believe serverexecute will be called multiple times until all data is received The TIdTCPServer.OnExecute event is fired in an endless loop for the lifetime of the TCP connection. The event doesn't care what data is transmitted. That is the responsibility of the code inside of the event to deal with as needed. Quote depending on your file size it may be chopped up into smaller chunks, usually like 1500 byte or so, depends on routers and os configs. That doesn't really matter in this case. ReadStream() will handle those chunks internally. The code's use of Write() is sending the file size followed by the file data. Then the code's use of ReadStream() is reading the file size and then reading the file data up to that size. Edited March 5, 2022 by Remy Lebeau Share this post Link to post
Remy Lebeau 1394 Posted March 5, 2022 (edited) 4 hours ago, MrCamarium said: the version of Indy is 10.5.7 That is an extremely old version of Indy, you should upgrade to the latest version, which is 10.6.2. Even if you can't upgrade your IDE. Edited March 5, 2022 by Remy Lebeau Share this post Link to post
MrCamarium 0 Posted March 5, 2022 6 hours ago, Remy Lebeau said: OK, thanks. The TIdTCPServer.OnExecute event is fired in an endless loop for the lifetime of the TCP connection. The event doesn't care what data is transmitted. That is the responsibility of the code inside of the event to deal with as needed. That doesn't really matter in this case. ReadStream() will handle those chunks internally. The code's use of Write() is sending the file size followed by the file data. Then the code's use of ReadStream() is reading the file size and then reading the file data up to that size. The test file is about 200K being local 127.0.0.1 should be fast transfer. At this point how do I know that the transfer is taking place? If I wanted to use a TProgressBar what should I do? Share this post Link to post
MrCamarium 0 Posted March 5, 2022 6 hours ago, Remy Lebeau said: That is an extremely old version of Indy, you should upgrade to the latest version, which is 10.6.2. Even if you can't upgrade your IDE. I downloaded the libraries but couldn't find a guide that tells me how to update the components. Inside the Lib folder there is a * .Bat file corresponding to each version of Delphi. I launched Fullc_XE2.bat but when I reopen my IDE I find the same version of Indy 10.5.7. Share this post Link to post
MrCamarium 0 Posted March 6, 2022 On 3/5/2022 at 1:34 AM, Remy Lebeau said: OK, thanks. The TIdTCPServer.OnExecute event is fired in an endless loop for the lifetime of the TCP connection. The event doesn't care what data is transmitted. That is the responsibility of the code inside of the event to deal with as needed. That doesn't really matter in this case. ReadStream() will handle those chunks internally. The code's use of Write() is sending the file size followed by the file data. Then the code's use of ReadStream() is reading the file size and then reading the file data up to that size. I figured out where I was wrong, the code works fine. In the server program as destination I did not give him the folder but the name of the file. Thank you! However, if you can suggest me a method with which I can monitor the sending I would be grateful. Share this post Link to post
Remy Lebeau 1394 Posted March 7, 2022 On 3/4/2022 at 10:38 PM, MrCamarium said: The test file is about 200K being local 127.0.0.1 should be fast transfer. At this point how do I know that the transfer is taking place? If I wanted to use a TProgressBar what should I do? You can use the connection's OnWork events for that purpose. Just be aware that they are fired in the context of the thread that is performing the transfer, so if that is not the main UI thread then you will have to synchronize your UI updates with the main thread. On 3/4/2022 at 10:42 PM, MrCamarium said: I downloaded the libraries but couldn't find a guide that tells me how to update the components. https://www.indyproject.org/2021/02/10/links-to-old-indy-website-pages-are-currently-broken/ https://web.archive.org/web/20200925081341/http://ww2.indyproject.org/Sockets/Docs/Indy10Installation.EN.aspx On 3/4/2022 at 10:42 PM, MrCamarium said: Inside the Lib folder there is a * .Bat file corresponding to each version of Delphi. I launched Fullc_XE2.bat That is a build script for C++Builder (hence the C in the filename), not for Delphi. Indy stopped using build scripts for Delphi after D2009. For Delphi, you can just open the project files directly in the IDE and use the Compile and Install options in the Project Manager. On 3/4/2022 at 10:42 PM, MrCamarium said: but when I reopen my IDE I find the same version of Indy 10.5.7. Of course, because 1) you didn't remove the old version from the IDE, and 2) the build script only compiles the library binaries, but it does not install them into the IDE. You have to do that step manually. On 3/5/2022 at 11:06 PM, MrCamarium said: I figured out where I was wrong, the code works fine. In the server program as destination I did not give him the folder but the name of the file. Thank you! Never use relative paths, always use absolute paths. 1 Share this post Link to post
MrCamarium 0 Posted March 8, 2022 (edited) Thank you! Edited March 8, 2022 by MrCamarium Share this post Link to post