Avatar billede hmann Nybegynder
21. april 2009 - 15:12 Der er 15 kommentarer og
1 løsning

Kopier fil over tcp forbindelse

Som et lille hjørne af et større projekt har jeg brug for at kopiere en fil fra en server til en klient.

Serverprogrammet skal af specielle årsager programmeres i D2007

Klientprogrammet sender en streng til serverprogrammet som udfører nogle ting på serveren, genererer en temporær fil, som klienten så modtager og gemmer lokalt.

Det lyder og burde være meget simpelt, men kan ikke få det til at virke. Bruger Indy 10 komponenter. Det er kun selve kopierings-delen jeg er i tvivl om. Jeg har prøvet med både de alm. tcpserver- og tcpclient-komponenterne og også indys FTP komponenter. Alle eksempler man kan finde på nettet er lavet vha Indy 9 og virker ikke med Indy 10.

Burde som sagt være simpelt. Noget i stil med at serversiden tager en fil og streamer den over til klienten via tcp-forbindelsen. Klienten samler streamen igen og gemmer den til en fil.

Synes efterhånden jeg har prøvet alt - uden held..


Nogen der har et fungerende eksempel eller input?
Avatar billede vallemanden Nybegynder
21. april 2009 - 15:26 #1
har selv været ude i noget af det samme, endte op med at bruge webcopy efter at serveren havde genereret filen

webcopy fra tmssoftware.com
Avatar billede kroning Nybegynder
21. april 2009 - 15:38 #2
Således sender jeg en fil fra min server til en klient, bruger Indy 10, jeg har fjernet en del kode for at gører det mere overskueligt, jeg håber ikke jeg har fjernet for meget

Server:

I IdTCPServerExecute:

procedure SendOpdatering;
var
  Stream : TFileStream;
begin
  try
        Stream:=TFileStream.Create(MinFil,fmOpenRead);
      try
        AContext.Connection.IOHandler.Write(Stream,0,true);
      finally
        Stream.Free;
      end;
  end;
  except
    on E: Exception do
    begin
      SkrivLog('Fejl i SendOpdatering: '+E.Message,true);
    end;
  end;
end;

----------------

Klient:

  TOpdateringThread = class(TThread)
  private
    { Private declarations }
    IdTCPClient: TIdTCPClient;
    Resultat,Update_mode : string;
    pBogLogon_md5 : string;

//    procedure HentFiler;
  protected
    procedure Execute; override;

  public
    ErrorStr : string;
    Svar : string;
    constructor Create(aHost, aBogLogon_md5 : string);
//    destructor Destroy; override;
  end;
.
.
.
constructor TOpdateringThread.Create(aHost : string);
begin
    inherited Create(False);
    FreeOnTerminate:=true;
  IdTCPClient:=TIdTCPClient.Create;
  IdTCPClient.ReadTimeout:=10000;
  IdTCPClient.ConnectTimeout:=5000;
  IdTCPClient.Port:=Bog_server_port;
  IdTCPClient.Host:=aHost;
  ErrorStr:='';
end;

procedure TOpdateringThread.Execute;
var
  Stream : TFileStream;
  Svar : TStringList;
  Sr: TSearchRec;
begin
  try
    IdTCPClient.Connect;
    Stream:=TFileStream.Create('update\'+minfil,fmCreate);
    IdTCPClient.IOHandler.ReadStream(Stream,-1,false);
    Stream.Free;
    except
        on E: Exception do begin
            Resultat:=Resultat+' - '+E.Message;
    end;
    end;

  IdTCPClient.Free;
end;
Avatar billede kroning Nybegynder
21. april 2009 - 15:40 #3
Jeg har ca. 30 klienter og der er efterhånden blevet overført tusinder af filer uden at jeg har oplevet problemer.
Avatar billede kroning Nybegynder
21. april 2009 - 15:44 #4
Glemte at nævne at i noget af den kode jeg har klippet der sender klienten først en lille streng til serveren med besked om at der skal sendes en fil hvorefter serveren sender en lille streng retur med filnavnet og derefter kommer så selve filen.
Avatar billede hmann Nybegynder
21. april 2009 - 16:01 #5
Takker..
Jeg har først tid til at afprøve det imorgen tidlig - skriver tilbage så snart det er testet..
Avatar billede hmann Nybegynder
21. april 2009 - 16:03 #6
Ligner nu meget det jeg selv har prøvet, men det får som sagt et forsøg imorgen
Avatar billede kroning Nybegynder
21. april 2009 - 16:27 #7
Jeg bruger Indy 10.2.3 og som nævnt virker ovenstående kode uden problemer. Hvis du ikke kan få det til at virker kan det måske være fordi du benytter en ældre Indy version som havde en hel del fejl.
Avatar billede hmann Nybegynder
22. april 2009 - 12:04 #8
Kan ikke få det til at virke :(

Har forsøgt at gøre det så simpelt som muligt ved at lave en serverapp kun med en tcpserver-komponent, hardcode host/port osv, og det samme med klienten, men noget går galt undervejs.

Klienten kommer med en 10022 - invalid arguments, når man siger connect.

Her er hvad jeg har:

Server:
-------------

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  Stream : TFileStream;
begin
  try
    Stream:=TFileStream.Create('c:\test.pdf',fmOpenRead);
    try
      AContext.Connection.IOHandler.Write(Stream,0,true);
    finally
      Stream.Free;
    end;
  except
    on E: Exception do
    begin
      ShowMessage('Fejl: '+E.Message);
    end;
  end;
end;




Klient:
--------------

  TOpdateringThread = class(TThread)
  private
    IdTCPClient: TIdTCPClient;
  protected
    procedure Execute; override;
  public
    constructor Create(aHost: string);
  end;

.
.
.

constructor TOpdateringThread.Create(aHost : string);
begin
  inherited Create(False);
  FreeOnTerminate:=true;
  IdTCPClient:=TIdTCPClient.Create;
  IdTCPClient.Port:=18000;
  IdTCPClient.Host:=aHost;
end;

.
.
.

procedure TOpdateringThread.Execute;
var
  Stream : TFileStream;
begin
  try
    IdTCPClient.Connect;
    Stream:=TFileStream.Create('c:\temp\bummelum.pdf',fmCreate);
    IdTCPClient.IOHandler.ReadStream(Stream,-1,false);
    Stream.Free;
    except
        on E: Exception do ShowMessage('Fejl: '+E.Message);
    end;

  IdTCPClient.Free;
end;

-----------

og så en knap på klienten som kreerer en tråd og kalder trådens execute procedure:


procedure TForm1.Button1Click(Sender: TObject);
var
  Thread: TOpdateringThread;
begin
  Thread := TOpdateringThread.Create('localhost');
  Thread.Execute;
end;

-----

har prøvet at køre både server og klient på localhost, men har også forsøgt at smide server app'en på en anden maskine - samme fejl..

hilfe bitte! :)
Avatar billede kroning Nybegynder
22. april 2009 - 16:46 #9
Thread.Execute; skal fjernes. Ændre det på noget? Hvis ikke så vil jeg prøve at teste din kode her.
Avatar billede hmann Nybegynder
22. april 2009 - 17:57 #10
har fjernet thread.execute fra min buttonclick - umiddelbart ser det ud til at virke! :)

men hvorfor? har ikke arbejdet meget med TThread's

Bliver thread'en "triggered" i createn, siden man ikke skal kalde execute?
Avatar billede kroning Nybegynder
22. april 2009 - 18:07 #11
Denne linie i trådens create:
inherited Create(False);
//constructor Create(CreateSuspended: Boolean);

angiver med false at tråden _ikke_ skal creates Suspended, dvs. at Execute kaldes automatisk straks efter at tråden er oprettet.

Så det også står i hjælpen:
Call Create to create a thread in an application. If CreateSuspended is False, Execute is called immediately. If CreateSuspended is True, Execute won't be called until after Resume is called.
Avatar billede kroning Nybegynder
22. april 2009 - 18:12 #12
Nu er det selfølgelig ikke et krav at du henter filen i en tråd men det giver jo den fordel at dit program ikke "hænger" mens filen hentes.
Du kan jo så benytte OnTerminate til at få at vide når filen er hentet.

F.eks:
TOpdateringThread.Create('localhost').OnTerminate:=MinOnTerminate;
.
.
procedure TForm1.MinOnTerminate(Sender: TObject);
begin
  ShowMessage('Fil hentet');
end;
Avatar billede hmann Nybegynder
22. april 2009 - 18:16 #13
ok tak for hjælpen!

smider du et svar?
Avatar billede kroning Nybegynder
22. april 2009 - 19:16 #14
Et svar
Avatar billede hmann Nybegynder
23. april 2009 - 08:13 #15
Et lille tillægsspørgmål -

Kan det være en fordel at skrive serverens onexecute ved hjælp af threads også, så den kan sende filer til flere klienter samtidigt, eller ligger det i serverkomponentens natur at den kan det?
Avatar billede kroning Nybegynder
23. april 2009 - 09:06 #16
Det styrer server komponenten automatisk, som du har lavet det nu kan serveren sende til mange på samme tid uden problemer.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester