AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi indy10 / TCPServer /TCPClient ->Datei versenden
Thema durchsuchen
Ansicht
Themen-Optionen

indy10 / TCPServer /TCPClient ->Datei versenden

Ein Thema von cherry · begonnen am 3. Apr 2008 · letzter Beitrag vom 18. Apr 2008
Antwort Antwort
Seite 2 von 3     12 3      
Benutzerbild von cherry
cherry

Registriert seit: 14. Nov 2005
561 Beiträge
 
RAD-Studio 2009 Ent
 
#11

Re: indy10 / TCPServer /TCPClient ->Datei versenden

  Alt 3. Apr 2008, 11:29
Ok, Ist zwar jetz nicht DIE Lösung, sondern eine Umgehung des Problems. Aber trotzdem, wie geht das jetzt mit der Progressbar?
Ist das nur mein Gefühl, oder ist die ganze Welt verrückt geworden!?
  Mit Zitat antworten Zitat
Benutzerbild von STS301
STS301

Registriert seit: 6. Nov 2007
668 Beiträge
 
Delphi 7 Personal
 
#12

Re: indy10 / TCPServer /TCPClient ->Datei versenden

  Alt 3. Apr 2008, 12:56
Delphi-Quellcode:
progressbar.min := 0;
 try
  //Anweisungen
  progressbar.Position:= 100;
finally
Sebastian

ölpölp

Linux will rule the universe!!
  Mit Zitat antworten Zitat
Benutzerbild von Der.Kaktus
Der.Kaktus

Registriert seit: 22. Jan 2008
Ort: Erfurt
958 Beiträge
 
Delphi 7 Enterprise
 
#13

Re: indy10 / TCPServer /TCPClient ->Datei versenden

  Alt 3. Apr 2008, 13:07
ich verweise auf meinen Tip im Beitrag #2 dieses Threads. Da steht alles beschrieben zwecks Progressbar beim Filetransfer.
Gruss Kaki

Repeat Until true=false;
  Mit Zitat antworten Zitat
Benutzerbild von cherry
cherry

Registriert seit: 14. Nov 2005
561 Beiträge
 
RAD-Studio 2009 Ent
 
#14

Re: indy10 / TCPServer /TCPClient ->Datei versenden

  Alt 4. Apr 2008, 07:08
hey... ich habs jetzt mal so gemacht. Es funktioniert allerdings nicht immer und nicht zuverlässig.
Was ich jetzt will ist: Der Client soll eine Datei an den Server schicken können aber vorab soll der name der zu schickenden Datei gesendet werden, damit dann der Server die Datei unter diesem Namen abspeichern kann. Dies hab ich mal probiert zu machen aber ich halte den Code für naja, unschön ist noch milde ausgedrückt.

Kurz: Wie kann ich verschiedene Sachen (Strings für Befehle, Anfragen und Meldungen und die Streams) kommunizieren ohne das es mir ein Durcheinander gibt? Ich kann ja nie wissen was ich gerade erhalten habe?

Mein momentaner CodeSalat:

Delphi-Quellcode:
procedure TForm1.EButton2Click(Sender: TObject);
var
  FStream: TFileStream;
begin
  try
    if OpenDialog1.Execute then
      begin
      if FileExists(OpenDialog1.FileName) then
      begin
        FStream := TFileStream.Create(OpenDialog1.FileName, fmOpenRead);
        TCPClient.Connect;
        TCPClient.IOHandler.WriteLn(ExtractName(Opendialog1.FileName));
        TCPClient.Disconnect;
        TCPClient.Connect;
        try
          TCPClient.IOHandler.Write(Fstream,0,true);
        finally
          FreeAndNil(FStream);
        end;
        if TCPClient.Connected then
          TCPClient.Disconnect;
      end
      else
        MessageDlg('file does not exist!', mtError, [mbOK], 0);
    end;
  except
    on e:Exception do
      MessageDlg(e.Message, mtError, [mbOK], 0);
  end;
end;

// TCP Server
procedure TForm1.TCPServerExecute(AContext: TIdContext);
var
  FSTream: TFileStream;
  df: String;
begin
  try
    if savefilepath = 'then
    begin
      savefilepath := DestinationEdit.Text+AContext.connection.IOHandler.ReadLn ;
      Memo1.Lines.Add('download file: "'+savefilepath+'" from '+AContext.Binding.PeerIP);
    end
    else
    begin
      try
        if FileExists(savefilepath) then
        begin
          if MessageDlg('overwrite existing file?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then
          begin
            df := savefilepath;
            DeleteFile(df);
            FStream := TFileStream.Create(savefilepath, fmCreate);
            AContext.connection.IOHandler.ReadStream(fstream);
          end;
        end
        else
        begin
          if DirectoryExists(ExtractFilePath(savefilepath)) = false then
            CreateDir(ExtractFilePath(savefilepath));
          FStream := TFileStream.Create(savefilepath, fmCreate);
          AContext.connection.IOHandler.ReadStream(fstream);
        end;
      finally
        FreeAndNil(FStream);
      end;
      AContext.connection.Disconnect;
    end;
    savefilepath := '';
  except
    on e:Exception do
      MessageDlg(e.Message, mtError, [mbOK], 0);
  end;
end;
Ist das nur mein Gefühl, oder ist die ganze Welt verrückt geworden!?
  Mit Zitat antworten Zitat
Benutzerbild von cherry
cherry

Registriert seit: 14. Nov 2005
561 Beiträge
 
RAD-Studio 2009 Ent
 
#15

Re: indy10 / TCPServer /TCPClient ->Datei versenden

  Alt 4. Apr 2008, 12:56
hey leuts

ich habe nun mein testprogramm fertiggestellt, es hat aber noch einen Fehler! und ich finde ihn nicht heraus! bin schon seit stunden dran und mir gehen langsam die ideeen aus. Manche Dateien kann ich übertragen andere nicht, manchmal geht diese und manchmal aber nur die andere.

Vielleicht schauts mal jmd von euch an?! wär echt toll!

TEButton / THideBox)

Danke schon mal zum Voraus

Liebe Grüsse

Cherry
Miniaturansicht angehängter Grafiken
netdownloader_661.jpg  
Angehängte Dateien
Dateityp: exe netdownloader_910.exe (598,5 KB, 17x aufgerufen)
Dateityp: rar netdownloader_153.rar (15,4 KB, 22x aufgerufen)
Ist das nur mein Gefühl, oder ist die ganze Welt verrückt geworden!?
  Mit Zitat antworten Zitat
Benutzerbild von DataCool
DataCool

Registriert seit: 10. Feb 2003
Ort: Lingen
909 Beiträge
 
Delphi 10.3 Rio
 
#16

Re: indy10 / TCPServer /TCPClient ->Datei versenden

  Alt 6. Apr 2008, 03:56
Hi,

ich hab mir bis jetzt zwar nur Deinen "Codesalat" hier angeschaut,
aber was Du brauchst ist definitiv eine saubere Serverstruktur und
ein kleines eigenes Protokoll.

- Du solltest vor dem Stream ein Text Commando zum Server schicken mit allen für den Transfer
nötigen Information z.B. FILETRANSFER||AUTOEXEC.BAT||348||OVERRIDEONSERVER

- Dann solltest Du auf jeden Fall Informationen zu dem jeweiligen Client in AContext.Data abspeichern;
ich benutze dazu oft folgendes :

Delphi-Quellcode:
unit JFIndy10BaseClientData;

// copyright by DataCool (at) gmx dot net
// in case of modifications please let me know

interface

uses IdContext;

Const

// predefined Status numbers

  cCSUnknown : Byte = 0;
  cCSJustConnected : Byte = 1;
  cCSGoing2Disconnect : Byte = 2;
  cCSDisconnected : Byte = 3;
  cCSWaiting4NextCmd : Byte = 4; // status after a noop cmd

type

  TIndyBaseClientData = class
    private
      // is a login necessary for this connection
      //fLoginRequired : Boolean;

      // login was successfull
      //fLoginOK : Boolean;

      // is a NOOP Command for this connection required ?
      fNoopRequired : Boolean;

      // Last-Command
      fLastCmd : String;

      // Last-Command as Integer, in case the server is working with integer commands
      fLastIntCmd : Word;

      // Last command time, necessary together with noops to detect dead client connections
      fLastCmdTime : TDateTime;

      // time of the connect of this connection
      fTimeOfConnect : TDateTime;
      
      // Status of this connection, maybe later on switch to type word, if a program requires more than 255 commands
      fStatus : Byte;

      // Indy-Context of this connection
      fContext : TIdContext;

      // procedures to set the last command,lastCmdTimd would be updated also
      procedure setStrCommand(Const Cmd : String);
      procedure setIntCommand(Const Cmd : Word);
    protected

    public
      Constructor Create(AContext : TIdContext);

      property Context : TIdContext read fContext;
      //property LoginRequired : boolean read fLoginRequired write fLoginRequired;
      //property LoginOk : boolean read fLoginOk write fLoginOk;
      property NoopRequired : Boolean read fNoopRequired write fNoopRequired;
      property LastCmd : String read fLastCmd write setStrCommand;
      property LastIntCmd : Word read fLastIntCmd write setIntCommand;
      property LastCmdTime : TDateTime read fLastCmdTime write fLastCmdTime;
      property TimeOfConnect : TDateTime read fTimeOfConnect write fTimeOfConnect;
      property Status : Byte read fStatus write fStatus;

      // isConnectionDead ?
  end;

implementation

uses SysUtils;

{ TIndyBaseClientData }

constructor TIndyBaseClientData.Create(AContext: TIdContext);
begin
  inherited Create;
  fContext := AContext;
  //fLoginRequired := true;
  //fLoginOK := false;
  fNoopRequired := false;
  fLastCmd := '';
  fLastIntCmd := 0;
  fLastCmdTime := 0;
  fTimeOfConnect := now;
  fStatus := cCSUnknown;
end;

procedure TIndyBaseClientData.setIntCommand(const Cmd: Word);
begin
  // dont compare cmd and fLastIntcommand, because perhaps the same cmd is coming 2 times
  fLastIntCmd := Cmd;
  fLastCmd := InttoStr(fLastIntCmd);
  // update also the last command time
  fLastCmdTime := now;
end;

procedure TIndyBaseClientData.setStrCommand(const Cmd: String);
begin
  // dont compare cmd and fLastcommand, because perhaps the same cmd is coming 2 times
  fLastCmd := Cmd;
  fLastIntCmd := StrToIntDef(fLastCmd,0);
  // update also the last command time
  fLastCmdTime := now;
end;

end.
Für die unterschiedlichen Projekte erstelle ich mir dann immer eine Klasse TClientData,
die von der oben genannten Klasse erbt/abgeleitet wird.

Im OnConnect des Servers erzeuge ich dann meine Klasse TClientData,
fülle diese mit Daten/Infos und lege Sie in AContext.Data ab.

Im OnExecute des Servers:
Delphi-Quellcode:
Var sUppCmd : String;
    sRawCmd : String;
    iPos : Longint;
    sParam : String;
    tmpClient : TClientData;
begin
  // Prüfen, ob Client Daten vorhanden sind
  // bei Indy10 wird das OnExecute auch einmalig ausgeführt, wenn die Connection des Clients im OnConnect getrennt wurde
  if not assigned(AThread.Data) then begin
    AContext.Connection.Disconnect;
    exit;
  end;
  // Client-Daten zu auslesen
  try
    tmpClient := TClientData(AThread.Data);
  except
    AContext.Connection.Disconnect;
    exit;
  end;

  if (tmpClient.Status = cCSGoing2Disconnect) or (tmpClient.Status = cCSDisconnected) then begin
    AContext.Connection.Disconnect;
    exit;
  end;
  try
    // Daten im Buffer ?
    tmpClient.LastCmd := AContext.Connection.Socket.ReadLn(#$A,Settings.CmdReadTimeOut,Settings.CmdMaxLength);
  except
    tmpClient.LastCmd := '';
  end;
  // Da das OnExecute des Server immer wieder eintritt bis der Client nicht mehr verbunden ist kann der obere Teil als
  // allgemeingültig bezeichnet werden. Je nach empfangenen Daten/Kommando jetzt weiter vorgehen

  // z.B.
  Case tmpClient.LastIntCommand of
    //
  end;
  // oder
  if tmpClient.LastCmd = 'YXZthen begin

  end;
  // ...
- Wichtig ! Im OnDisconnect müssen die Daten des Clients auch wieder freigegeben werden
Delphi-Quellcode:
Var tmpClient : TClientData;
begin
  // valid data in . data
  if Assigned(AContext.Data) then begin
    // try to cast the data to TClientData
    try
      tmpClient := TClientData(AContext.Data);
    except
      tmpClient := Nil;
    end;
    // Cast successfull ?
    if Assigned(tmpClient) then
      FreeAndNil(tmpClient)
    // !!!! very imported to set AContext.Data to nil !!!!!
    AContext.Data := Nil;
  end;
end;
Ich hoffe ^das^ hat erstal ein groben Überblick/Denkanstoss geschaffen,
wie man sowas realisieren könnte.
Außerdem sollte im Servercode kein MessageDlg verwendet werden,
ein Server sollte selbstständig und OHNE Interaktion mit dem User laufen.
Am besten sogar ganz ohne GUI als Dienst.

Greetz DataCool
Der Horizont vieler Menschen ist ein Kreis mit Radius Null, und das nennen sie ihren Standpunkt.
  Mit Zitat antworten Zitat
Benutzerbild von STS301
STS301

Registriert seit: 6. Nov 2007
668 Beiträge
 
Delphi 7 Personal
 
#17

Re: indy10 / TCPServer /TCPClient ->Datei versenden

  Alt 6. Apr 2008, 11:28
mit der Grafik musst du dir noch was einfallen lassen, beim 20 Zoll sieht das so aus:
Angehängte Grafiken
Dateityp: bmp neues_bild_933.bmp (328,1 KB, 66x aufgerufen)
Sebastian

ölpölp

Linux will rule the universe!!
  Mit Zitat antworten Zitat
busybyte

Registriert seit: 15. Sep 2006
165 Beiträge
 
#18

Re: indy10 / TCPServer /TCPClient ->Datei versenden

  Alt 6. Apr 2008, 14:40
http://www.indyproject.org/docsite/h...StreamVCL.html

Mann ist die Indyhilfe bescheiden...irgendwann erscheint der Button Home auf dem Link und dann eine Suchleiste,darin findet man z.B.
idStream.write und dort sieht man dann die benötigte Unit.

Topic Path: Symbol Reference > Types > TIdStream Type
ContentsIndexHome

PreviousUpNext
TIdStream Type
Collapse All

Implements a stream wrapper for the platforms supported by the Indy library.
File

IdObjs
Pascal

TIdStream = TStream;

Description

TIdStream is a TObject descendant that specifies a wrapper for stream classes. TIdStream isolates the differences between stream implementations for the platforms supported by the Indy library.

To minimize the number of overloaded methods required for TStream and .Net Stream arguments, TIdStream provides an implict converter as a class operator for VCL to .Net stream types.

TIdStream overrides provides methods used for reading and writing to the stream that isolate the differences between pointers and memory allocation for the .Net platform.
See Also

TIdBytes
Copyright © 1993-2006, Chad Z. Hower (aka Kudzu) and the Indy Pit Crew. All rights reserved.
Post feedback to the Indy Docs Newsgroup.



Uses idObjs; //ist ja auch völlig logisch, lol,ob die wohl Drogen konsumieren?
I love DiscCat
  Mit Zitat antworten Zitat
Benutzerbild von cherry
cherry

Registriert seit: 14. Nov 2005
561 Beiträge
 
RAD-Studio 2009 Ent
 
#19

Re: indy10 / TCPServer /TCPClient ->Datei versenden

  Alt 7. Apr 2008, 11:11
Zitat von DataCool:
Ich hoffe ^das^ hat erstal ein groben Überblick/Denkanstoss geschaffen,
wie man sowas realisieren könnte.
Außerdem sollte im Servercode kein MessageDlg verwendet werden,
ein Server sollte selbstständig und OHNE Interaktion mit dem User laufen.
Am besten sogar ganz ohne GUI als Dienst.

Greetz DataCool
naja, also das mit den Dialogen im Servercode habe ich bereits selber rausbekommen und entsprechend geändert.

Ich hab mir also mal deine Unit "JFIndy10BaseClientData" nachgebaut und versucht zu implementieren. Dabei bin ich gleich auf ein Problem(chen) gestossen. Und zwar im OnExecute Event vom Servercode:


Delphi-Quellcode:
// Client-Daten zu auslesen
  try
    tmpClient := TClientData(AThread.Data);
  except
    AContext.Connection.Disconnect;
    exit;
  end;
Ich denke da hast du noch was von einer älteren Indy-version vermischt. Habe einfach "AThread.Data" in "AContext.Data" geändert. Aber jetzt das eigentliche Problem(chen):

Delphi-Quellcode:
try
    // Daten im Buffer ?
    tmpClient.LastCmd := AContext.Connection.Socket.ReadLn(#$A,Settings.CmdReadTimeOut,Settings.CmdMaxLength);
  except
    tmpClient.LastCmd := '';
  end;
Ich kann nicht auf "Settings" zugreiffen (Nicht def. Bezeichner)... woher genau soll das kommen? hab ich was verpasst?

Ansonsten finde ich den Ansatzt sehr gut und hoffe den so implementieren zu können das alles nach meinen Vorstellungen klappt.
Noch was, wieso soll das Ganze am besten ohne GUI und noch besser als Dienst laufen?! Wenn ich ein anständiges exception handling
mache sollte das doch kein Problem sein?!


Nun noch eine Frage zum Senden der Datei

Kann ich das jetzt so machen:

Delphi-Quellcode:
  FStream := TFileStream.Create(uploadfilepath, fmOpenRead or fmShareDenyWrite);
  TCPClient.Connect;
  try
    TCPClient.IOHandler.Write(Fstream,0,true);
  finally
    FreeAndNil(FStream);
  end;
oder muss ich den Stream umwandeln? Wenn ja wie und in was? vielleicht so?:

Delphi-Quellcode:
// Send TCP Stream
procedure TForm1.TCPSendStream(Stream: TFileStream);
var
  IdStream: TIdStream;
begin
  IdStream:= TIdStream.Create;
  IdStream.CopyFrom(Stream,SizeOf(Stream));
  TCPClient.Connect;
  TCPClient.IOHandler.Write(IdStream,0,true);
  TCPClient.Disconnect;
end;
Naja ich dank euch schon mal allen für die tolle Hilfe...
wär genial wenn ihr mich noch ein bisschen begleiten würdet, bis ich dann auf eigenen Füssen stehen kann... hehe
Ist das nur mein Gefühl, oder ist die ganze Welt verrückt geworden!?
  Mit Zitat antworten Zitat
Benutzerbild von DataCool
DataCool

Registriert seit: 10. Feb 2003
Ort: Lingen
909 Beiträge
 
Delphi 10.3 Rio
 
#20

Re: indy10 / TCPServer /TCPClient ->Datei versenden

  Alt 7. Apr 2008, 14:49
Hi Cherry,

Du hast recht ich habe ^den^ Source mal eben von Indy9 auf Indy10 portiert,
damit Du was damit anfangen kannst.

Hier eben die kleinen Portierbugs behoben:

Delphi-Quellcode:
  // Client-Daten zu auslesen
  try
    tmpClient := TClientData(AContext.Data);
  except
    AContext.Connection.Disconnect;
    exit;
  end;
Delphi-Quellcode:
  try

    // Settings.CmdReadTimeOut <-- meine Einstellungsklasse der WErt des ReadlnTimeOutsfür Kommandos
    // Settings.CmdMaxLength <-- meine Einstellungsklasse der Wert der maximalen Zeichenlänge mein ReadLn

    // Daten im Buffer ? 5000 ms = 5 Sekunden ReadLn-Timeout, maximal 1024 lesen
    // die Parameter beim ReadLn sind optional und müssen nicht zwingend verwendet werden
    tmpClient.LastCmd := AContext.Connection.Socket.ReadLn(#$A,5000,1024);
  except
    tmpClient.LastCmd := '';
  end;
Zum Senden einer Datei via Stream; Ich kann Dir jetzt nicht mit 100% Sicherheit sagen wie's gemacht wird,
weil ich meine akztuellen Projekte alle noch in Indy9 habe und bald erst mit dem portieren anfange.
Was ich aber festgestellt habe ist das es in Indy10 kein "WriteStream" mehr gibt, obwohl ein "ReadStream"
gibt. Ich habe aber auch gesehen das es bei Indy10 jetzt ein WriteFile gibt und wenn man sich den Source dazu anschaut :

Delphi-Quellcode:
function TIdIOHandler.WriteFile(const AFile: String; AEnableTransferFile: Boolean): Int64;
var
//TODO: There is a way in linux to dump a file to a socket as well. use it.
  LStream: TIdStream;
begin
  EIdFileNotFound.IfFalse(Sys.FileExists(AFile), Sys.Format(RSFileNotFound, [AFile]));
  LStream := TReadFileExclusiveStream.Create(AFile); try
      Write(LStream);
      Result := LStream.Size;
  finally Sys.FreeAndNil(LStream); end;
end;
^^ Da könntest Du Dir die Vorgehensweise abschauen.

Jetzt nochmal zu der Frage warum ich keine GUI verwenden würde :

Wenn es nachher ein produktiver Server ist, soll er vor allem eins : Laufen ohne abzustürzen
Eine hohe Ausfallsicherheit erreichst man unter anderem auch, indem man die Fehlerquellen minimiert,
wenn Du mit einer GUI in einem Multi-Threaded Server arbeitest, solltest alle Änderungen an der GUI
nur syncronisiert vorgenommen werden, ansonsten könne recht "unschöne" Sachen passieren und Du denkst
Dein Server läuft noch obwohl er nicht mehr richtig arbeitet.
Klar kannst Du, wenn Du sauber programmierst das ganze auch mit GUI machen, ich wollte Dich nur auf die Gefahren hinweisen

Versteh mich nicht falsch ich habe zu meinen "Servern" auch eine GUI aber das ganze läuft bei mir so :
- Server wird als Dienst geschrieben, hat keine Gui und keine Interaktion mit dem Desktop
- Im Server wird ein zusätzlicher Port nur lokal geöffnet
- Dann schreibe ich meine "GUI zum Server" als eigene Anwendung, die dann über den lokalen Port sich
die Infos die sie braucht holt und anzeigt.
- die lokale Kommunikation zwischen Server-GUI und Server-Dienst ist natürlich verschlüsselt und die GUI
muss sich natürlich erst beim connecten verifizieren.

^^ Aber das must Du jetzt nicht alles machen, man muss ja auch nicht mit Kanonen auf Spatzen schiessen

Alles nur Denkanstösse,

Greetz DataCool
Der Horizont vieler Menschen ist ein Kreis mit Radius Null, und das nennen sie ihren Standpunkt.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 3     12 3      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:34 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz