Einzelnen Beitrag anzeigen

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, 02: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