AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi Client-Server-Programm mit Indy9 und D6Pro zur Begutachtung
Thema durchsuchen
Ansicht
Themen-Optionen

Client-Server-Programm mit Indy9 und D6Pro zur Begutachtung

Ein Thema von DaniU · begonnen am 20. Apr 2005
Antwort Antwort
DaniU

Registriert seit: 8. Apr 2005
Ort: Untersiggenthal
1 Beiträge
 
Delphi 6 Professional
 
#1

Client-Server-Programm mit Indy9 und D6Pro zur Begutachtung

  Alt 20. Apr 2005, 15:38
Hallo zusammen
Ich probier nun schon seit Tagen (bald Wochen) an einem Client-Server Programm mit D6 Pro und den Indy9 Komponenten (TIdTCPClient, TIdTCPServer). Das ganze ist zurzeit Neuland für mich. Da ich in diesem Forum am meisten zu den Indy Komponenten gefunden habe, möchte ich mein Projekt hier zur Begutachtung (und Vorschläge zur Verbesserung entgegennehmen) unterbreiten.
Das Projekt baut auf einem sehr guten Forumsbeitrag vom Jan 2004 von negaH auf.

Da ich kein Profiprogrammierer bin hat es viele Unschönheiten im Code. Ich bitte Euch das Augenmerk vor allem auf die IP-Kommunikation zwischen Server und Client und umgekehrt zu richten.

Die aktuellen Unklarheiten:
- Im Client habe ich eine Schleife 'Repeat .... until False' eingebaut. Wahrscheinlich würde das auch besser anders gehen.
- Die Function 'Readkundendatei' ist praktisch gleich wie die Function 'ReadString' (im Client). Die liessen sich wahrscheinlich in einer Function zusammenfassen (wenn man wüsste wie, in den Functionen ReadByte und ReadString sehe ich nicht so durch).
- Ich sende zuerst die Grössenangabe der zu sendenden Datei an den Client, anschliessend wird die Datei mit dieser Grössenangabe vom Client entgegengenommen. Das lässt sich sicher viel besser machen.

Idee des Projektes:
Der Client meldet sich mit seiner Kennung am Server an. Nach der Antwort vom Server sendet der Client
dem Server eine Kundennummer und ein bestimmtes Merkmal (z.B. 000456765ALL (das mit dem Merkmal ist in der vorliegenden QuellcodeForm noch nicht drin)). Der Server nimmt die Kundennnummer entgegen liest die zugehörige Textdatei von der Disk ein. Filtert die entsprechenden Datensätze je nach Merkmal heraus und sendet das Ergebnis dem Client. Der Client nimmt die Daten entgegen, sendet dem Server eine Trennanforderung, und zeigt die erhaltenen Daten dem Bediener an.

Bemerkung zur Beilage:
Das Projekt liegt dem Beitrag als Zip-Datei (mit Quellcode und kompiliert) bei. Die Zipdatei bitte mit Ordnerstruktur entpacken, dann funktionierts auf Anhieb.

Untenstehend habe ich den Code des Servers und Client gepostet. Wahrscheinlich könnt Ihr aufgrund dessen bereits ein paar Tips abgeben.

Danke für Eure Stellungnahme, Kommentare und Hilfe.

Gruess
Dani

Quellcode des Servers für IP- Kommunikation:
Delphi-Quellcode:
procedure TFrmHaupt.IdTCPServer1Execute(AThread: TIdPeerThread);
var
  SessionID: Integer;
  // ----------------
  procedure DoLog(const Msg: String); // Log schreiben
  var
    S: String;
    I: Integer;
    DatumZeit : String;
  begin
    DateTimeToString (DatumZeit,'hh:nn:ss:zzz', Now); // Aktuelles Datum eintragen zzz ist millisekunden
    Memo1.Lines.Add('ID:' + IntToStr (SessionID) + '-' + Datumzeit + ':' + Msg );
  end;
  // ----------------
  function ReadByte: Byte;
  begin
    AThread.Connection.ReadBuffer(Result, SizeOf(Result));
  end;
  // ----------------
  function ReadLong: Cardinal;
    function SwapLong(Value: Cardinal): Cardinal;
    // konvertiert Big Endian zu Little Endian
    // im INet ist es üblich ALLE Daten in Big Endian zu übertragen
    asm
      BSWAP EAX
    end;

  begin
    AThread.Connection.ReadBuffer(Result, SizeOf(Result));
    Result := SwapLong(Result);
  end;
  // ----------------
  function ReadString: String;
  begin
    SetLength (Result, ReadByte);
    AThread.Connection.ReadBuffer (Result[1], Length(Result));
  end;
  // ----------------
  procedure WriteByte (Value: Byte);
  begin
    AThread.Connection.WriteBuffer (Value, SizeOf(Value));
  end;
  // ----------------
  procedure WriteString(const Value: String);
  begin
    WriteByte(Length(Value));
// DoLog ('SERVER: Procedure WriteString, Länge des Strings:' + IntToStr (Length(Value)) + ', StringInhalt:' + Value);
    AThread.Connection.WriteBuffer (Value[1], Length(Value));
  end;
  // ----------------

var
  KdNr : String;
  KundenDaten : String;
  DateiGroesse: String;

begin // ------------ Hauptprocedur von ServerExecute --------------------
  SessionID := LastSessionID;
  Inc (LastSessionID);

  DoLog ('TFrmHaupt.IdTCPServer1Execute(AThread: TIdPeerThread); gestartet ===============');
  try
    if (ReadByte = 1) and (ReadString = 'Preisliste@Web') then begin // LOGIN
      DoLog ('ReadByte=1 und ReadString=Preisliste@Web vom Client erhalten.');
    // Client hat sich korrekt identifiziert sende Bestätigung und warte auf Kommandos
      WriteByte (1);
      DoLog ('WriteByte=1 an Client gesendet.');
      while True do begin
        case ReadByte of
          0: begin // NULL
               DoLog ('SERVER: ReadByte=0 vom Client erhalten');
               WriteByte (0);
             end;
          2: begin // LOGOUT
               DoLog ('SERVER: ReadByte=2, Abmeldeanforderung vom Client erhalten.');
               Break;
               DoLog ('SERVER: Break, Client meldet ab');
             end;
          3: begin // ERROR
               DoLog (Format ('SERVER: ReadByte=3, Client Fehler %d, %s', [ReadByte, ReadString]));
               Break; // Fehler führt IMMER zum Abbau der Verbindung
             end;
          4: begin // Text senden
               // Zu aufbereitende Kundennummer vom Client lesen Anfang
               DoLog ('Readbyte=4, Aufzubereitende KdNr wird nun vom Client gesendet.');
               KdNr := ReadString;
               DoLog ('ReadString Aufzubereitende KdNr vom Client erhalten:' + KdNr + '<');
               // Zu aufbereitende Kundennummer vom Client lesen Ende

               // Kundendaten aufbereiten Anfang
               KundenDaten := KundenDatenAufbereiten (KdNr, DateiGroesse, SessionID);
               // Kundendaten aufbereiten Ende

               // Dateigrösse an Client senden Anfang
               WriteByte (6);
               DoLog ('WriteByte=6, Dateigrösse der zu sendenden KdDaten wird nun an den Client gesendet.' );
               WriteString (DateiGroesse);
               DoLog ('WriteString='+DateiGroesse+', (Dateigrösse) an Client gesendet.');
               // Dateigrösse an Client senden Ende

               // Kundendatei an Client senden Anfang
               WriteByte (5);
               DoLog ('WriteByte=5, Gesamte Kundendatei wird nun an den Client gesendet.');
               WriteString (KundenDaten);
               DoLog ('WriteString="Gesamter Inhalt der Kundendatei" an Client gesendet');
               // Kundendatei an Client senden Ende
             end;
        else
          begin // Invalid Code;
            DoLog ('Hier wäre ein Break, Readbyte ist <> 0,2,3,4');
            WriteByte (3);
            DoLog ('WriteByte=3 gesendet');
            WriteByte (0); // Errorcode
            DoLog ('WriteByte=0 gesendet');
            WriteString ('ungültiger Befehl');
            DoLog ('WriteString="ungültiger Befehl" an Client gesendet');
            Sleep (1);
// Break;
            DoLog ('Hier wäre ein Break');
          end;
        end;
      end; // falsches/fehlendens Client-Login, trenne einfach die Verbindung, Server ist im Stealth mode
    end
    Else begin
      DoLog ('ReadByte=? und ReadString=? vom Server erhalten -> Login geht nicht');
    End;
  finally
    DoLog ('Finally, Client Verbindung geschlossen.');
    try
      Sleep (1);
      AThread.Connection.Disconnect;
      DoLog ('Finally -> Try, AThread.Connection.Disconnect;');
    except
      DoLog ('Finally -> Try -> Except, Irgendein Fehler ist passiert.');
    end;
  end;
  DoLog ('TFrmHaupt.IdTCPServer1Execute(AThread: TIdPeerThread); ende der Schlaufe ============');
end;
Quellcode des Clients für IP- Kommunikation:
Delphi-Quellcode:
procedure TFrmHaupt.DatenAnServerSenden (VonWoKommtAufruf : String);
Var DateiGroesse : String;
  // ----------------
  procedure DoLog(const Msg: String); // Log schreiben
  var
    DatumZeit : String;
  begin
    DateTimeToString (DatumZeit,'hh:nn:ss:zzz', Now); // Aktuelles Datum eintragen zzz ist millisekunden
    Memo1.Lines.Add (Msg + '-' + Datumzeit);
  end;
  // ----------------
  procedure WriteByte (Value: Byte);
  begin
    TCP.WriteBuffer (Value, SizeOf(Value));
  end;
  // ---------------
  procedure WriteString (const Value: String);
  begin
    WriteByte (Length (Value));
    TCP.WriteBuffer (Value[1], Length (Value));
  end;
  // ---------------
  function ReadByte: Byte;
  begin
    TCP.ReadBuffer (Result, SizeOf (Result));
// showmessage (inttostr (ord(65))); // ergibt -> A
    DoLog ('CLIENT:In Funct ReadByte. ASCII-Wert vom gelesenen Byte:' + IntToStr (Ord(Result))); // IntToStr(Ord('c')) chr(65) ergibt A
  end;
  // ---------------
  function ReadString: String;
  begin
    SetLength (Result, ReadByte);
    TCP.ReadBuffer (Result[1], Length (Result));
  end;
  // ---------------
  function ReadKundenDatei: String;
  begin
    SetLength (Result, StrToInt(DateiGroesse)-1) ;
    TCP.ReadBuffer (Result[1], Length (Result));
  end;
  // ---------------

begin // // --------------- Client Hauptprocedur -------------------------
  Randomize; // Zufallszahlen initialisieren
  TCP.Host := EdtServerIP.Text;
  DoLog (VonWoKommtAufruf);
  try
    try
      TCP.Connect;
      DoLog ('CLIENT: TCP.Connect -> Kommunikation mit Server aufgenommen.');
      WriteByte (1);
      DoLog ('CLIENT: WriteByte=1 an Server gesendet.');
      WriteString ('Preisliste@Web');
      DoLog ('CLIENT: WriteString, "Preisliste@Web" an Server gesendet.');
      Repeat
        case ReadByte of
          1: begin
               DoLog ('CLIENT: ReadByte=1 vom Server erhalten.');
               WriteByte(4);
               DoLog ('CLIENT: WriteByte=4 an Server gesendet.');
               KdNrTmp := KundenListe.Strings[Random (5)]; //Zufallswert aus der Kundenliste nehmen
               WriteString (KdNrTmp);
               DoLog ('CLIENT: WriteString, KdNr: ' + KdNrTmp + ', an Server gesendet. Anforderung der Kundendaten');
             end;
          3: begin
               DoLog ('CLIENT: ReadByte=3 vom Server erhalten.');
               ShowMessage(Format('Fehler %d, %s', [ReadByte, ReadString]));
             end;
          5: begin // Kundendatei vom Server lesen
               DoLog ('CLIENT: ReadByte=5 vom Server erhalten.');
               KundenDaten := ReadKundenDatei ;
               KundenDatenLokalSpeichern (KundenDaten, KdNrTmp);
               DoLog ('CLIENT: ReadString, vom Server erhalten: GesamteKundenDatei');
               DoLog ('CLIENT: Länge ReadString:' + IntToStr (Length(KundenDaten)) + '<');

               WriteByte(2); // Abmeldeanforderung an Server senden
               DoLog ('CLIENT: WriteByte=2 an Server gesendet (Disconnectanforderung)');
               DoLog ('CLIENT: "Repeat .... Until False" wird nun mit Exit beendet');
               Exit;
             end;
          6: begin // Dateigrösse der zu lesenden Datei vom Server lesen
               DoLog ('CLIENT: ReadByte=6 (DateiGroesse) vom Server erhalten.');
               DateiGroesse := ReadString ;
               DoLog ('CLIENT: ReadString, vom Server erhalten (DateiGroesse):' + DateiGroesse + '<');
             end;
        else
          DoLog ('CLIENT: ReadByte=? vom Server erhalten. Ungültiger Antwortcode.');
          ShowMessage('Ungültiger Antwortcode.');
        end;
      Until False; // unendliche Schlaufe
    finally
      TCP.Disconnect;
      DoLog ('CLIENT: Finally, tcp.disconnect =============================================================');
    end;
  except
    on E: Exception do
      DoLog ('CLIENT: on Exception:' + E.Message);
  end;
  DoLog ('CLIENT: Ende Schlaufe Daten an Server senden =============================================================');
End;
Angehängte Dateien
Dateityp: zip clientserverindy9d6pro_104.zip (517,6 KB, 24x aufgerufen)
Gruess
  Mit Zitat antworten Zitat
Antwort Antwort


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 16:32 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