|
Antwort |
Registriert seit: 8. Apr 2005 Ort: Untersiggenthal 1 Beiträge Delphi 6 Professional |
#1
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:
Quellcode des Clients für IP- Kommunikation:
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;
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;
Gruess
|
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs 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
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |