AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi Probleme mit Server-Client-Programmierung (Indy10)
Thema durchsuchen
Ansicht
Themen-Optionen

Probleme mit Server-Client-Programmierung (Indy10)

Ein Thema von albert1985 · begonnen am 28. Jan 2007 · letzter Beitrag vom 28. Jan 2007
Antwort Antwort
albert1985

Registriert seit: 14. Jan 2007
38 Beiträge
 
Delphi 7 Personal
 
#1

Probleme mit Server-Client-Programmierung (Indy10)

  Alt 28. Jan 2007, 12:57
Hi,

Also so langsam bin ich noch am verzweifeln ... Ich versuche schon längere Zeit mich mit der
Server-Client Programmierung zu beschäftigen, hab auch schon alle mögliche Demos etc., die ich gefunden hab
durchprobiert, aber leider sind die meistens für mich zu komplex ...
Ich bin absoluter Beginner und würde mich gerne mit indy10 näher beschäftigen. Leider
habe ich selbst Probleme die Schritte beim Connecten des Clienten zum Server zu verstehen ...

Hoffe ihr könnt mir dabei etwas behilflich sein
Hier erstmal der Teil den ich verstanden hab ... (hab zwei Edit Felder und ein Connect Button)
Delphi-Quellcode:
with IdTCPClient1 do try
    Host := HostEdit.text;
    Port := StrToInt(portEdit.text);
    Connect;
Nun möchte ich es zB ermöglichen das ich einen befehl an den Server schicke, der zB einen "MessagDlg"
ausgibt ...

Es würde mir SEHR weiterhelfen, wenn mir jemand genau erklären könnte wie dass mit ReadLn/WriteLn etc. funktioniert ... Also auch so, dass ich verstehe, was diese "Befehle" überhaupt genau bewirken und wie ich das serverseitig "abfangen" kann ... Danke schonmal im Vorraus

M f G
"Was machen Sie? – Wie? Machen? – Ich meine beruflich… – Wieso? Damit Sie Interesse heucheln können?"
  Mit Zitat antworten Zitat
albert1985

Registriert seit: 14. Jan 2007
38 Beiträge
 
Delphi 7 Personal
 
#2

Re: Probleme mit Server-Client-Programmierung (Indy10)

  Alt 28. Jan 2007, 16:15
Also bin jetzt schon selbst etwas weitergekommen ! Gibt aber immer noch Probleme ...

Hab jetzt folgenden Quelltext für den Client:
Delphi-Quellcode:
procedure TForm1.NachrichtButtonClick(Sender: TObject);
begin
  if IdTCPClient1.Connected = true then begin
    with IdTCPClient1 do try
      IOHandler.WriteLn('MSG');
    finally end;
  end;
end;
und entsprechend für den reagierenden Client:

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
  IdTCPServer1.Active := True;
  with IdTCPServer1.Bindings.Add do
  begin
    IP:='127.0.0.1'; // zum Testen 127.0.0.1 ...
    Port:=3666; // Kann man hier einen beliebigen freien Port wählen?
  end;
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  Line : String;
begin
  Line := AContext.Connection.IOHandler.ReadLn;
    if Line = 'MSGthen
    MessageDlg('Huhu - der Client hat sich verbunden',mtInformation,[mbOK],0);
end;
1. Ist dieser Code so in etwa richtig, wenn ich die besagte Meldung anzeigen lassen will??
2. Es erscheint wenn ich beide Programme ausführe ein Fehler der besagt : Connection Timeout / Connection refused
woran kann das liegen ?

MfG
"Was machen Sie? – Wie? Machen? – Ich meine beruflich… – Wieso? Damit Sie Interesse heucheln können?"
  Mit Zitat antworten Zitat
Benutzerbild von inherited
inherited

Registriert seit: 19. Dez 2005
Ort: Rosdorf
2.022 Beiträge
 
Turbo Delphi für Win32
 
#3

Re: Probleme mit Server-Client-Programmierung (Indy10)

  Alt 28. Jan 2007, 17:11
Du musst im Client den Host auf 127.0.0.1 und den Port auf einen bliebigen Integerwert setzen. Bei dem Server Defaultport auf den gleichen wert und active auf true. Dann kannst du dir das mit den Bindings sparen und müsste funktionieren.
Nikolai Wyderka

SWIM SWIM HUNGRY!
Neuer Blog: hier!
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#4

Re: Probleme mit Server-Client-Programmierung (Indy10)

  Alt 28. Jan 2007, 17:28
Zitat von inherited:
den Port auf einen bliebigen Integerwert setzen
Hi,
das ist so nicht korrekt. Kann zwar auf dem eigenen System klappen, muss es aber schon nicht. Es gibt verschiedene Gruppen von Ports, die Ports von 0-1023 sind sogenannte "Well-Known-Ports". Diese sind alle festen Diensten zugeordnet, die sich natürlich nicht an diese Ports halten müssen, aber es ist davon auszugehen, dass viele der Dienste auch wirklich auf diesen Ports laufen und entsprechend Anfragen auf diesen Ports gestellt werden.
Die Ports 1024 - 49151 sind dann die "registered-Ports". Diese Ports wurden bereits für bestimmte Anwendungen (besser gesagt ein Teil der Ports) registriert. Hier spricht einiges dafür, dass eine Verbindung auf einem dieser Ports auch zu der entsprechenden Anwendung gehört. Das heißt für Dich vor allem, dass hier schon ein Dienst laufen kann, aber eben auch, dass dein Programm durch den Port leicht für ein laufendes anderes gehalten werden könnte.
Die restlichen Ports 49152 - 65531 sind dann die "Private-Ports", hier gibt es keine festen Zuordnungen, schnapp Dir einen Port der frei ist und mach was Du willst

Gruß Der Unwisssende
  Mit Zitat antworten Zitat
albert1985

Registriert seit: 14. Jan 2007
38 Beiträge
 
Delphi 7 Personal
 
#5

Re: Probleme mit Server-Client-Programmierung (Indy10)

  Alt 28. Jan 2007, 17:42
Danke für die Antworten

Ich weiß jetzt auch was bei mir falsch war... Ich hätte anstatt "Port" "DefaultPort" schreiben müssen ...
Sonst kann das natürlich nicht funktioniern !
"Was machen Sie? – Wie? Machen? – Ich meine beruflich… – Wieso? Damit Sie Interesse heucheln können?"
  Mit Zitat antworten Zitat
Benutzerbild von inherited
inherited

Registriert seit: 19. Dez 2005
Ort: Rosdorf
2.022 Beiträge
 
Turbo Delphi für Win32
 
#6

Re: Probleme mit Server-Client-Programmierung (Indy10)

  Alt 28. Jan 2007, 18:05
Zitat von Der_Unwissende:
Zitat von inherited:
den Port auf einen bliebigen Integerwert setzen
Hi,
das ist so nicht korrekt. Kann zwar auf dem eigenen System klappen, muss es aber schon nicht. Es gibt verschiedene Gruppen von Ports, die Ports von 0-1023 sind sogenannte "Well-Known-Ports". Diese sind alle festen Diensten zugeordnet, die sich natürlich nicht an diese Ports halten müssen, aber es ist davon auszugehen, dass viele der Dienste auch wirklich auf diesen Ports laufen und entsprechend Anfragen auf diesen Ports gestellt werden.
Die Ports 1024 - 49151 sind dann die "registered-Ports". Diese Ports wurden bereits für bestimmte Anwendungen (besser gesagt ein Teil der Ports) registriert. Hier spricht einiges dafür, dass eine Verbindung auf einem dieser Ports auch zu der entsprechenden Anwendung gehört. Das heißt für Dich vor allem, dass hier schon ein Dienst laufen kann, aber eben auch, dass dein Programm durch den Port leicht für ein laufendes anderes gehalten werden könnte.
Die restlichen Ports 49152 - 65531 sind dann die "Private-Ports", hier gibt es keine festen Zuordnungen, schnapp Dir einen Port der frei ist und mach was Du willst

Gruß Der Unwisssende
Dessen bin ich mir wohl bewusst, nur würde das zu erklären zu sehr vielen verwirrungen seiner seits führen, was widerrum nicht der Sinn eines Forums dieser Art sein sollte. Was also soll es, ihn jetzt mit so vielen neuen Begriffen zu verwirren?
Nikolai Wyderka

SWIM SWIM HUNGRY!
Neuer Blog: hier!
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#7

Re: Probleme mit Server-Client-Programmierung (Indy10)

  Alt 28. Jan 2007, 18:33
Hi, nochmal etwas ausführlicher zu deinem Problem:

Zitat von albert1985:
Ich versuche schon längere Zeit mich mit der
Server-Client Programmierung zu beschäftigen, hab auch schon alle mögliche Demos etc., die ich gefunden hab
durchprobiert, aber leider sind die meistens für mich zu komplex ...
Ich bin absoluter Beginner und würde mich gerne mit indy10 näher beschäftigen. Leider
habe ich selbst Probleme die Schritte beim Connecten des Clienten zum Server zu verstehen ...
An sich ist die Arbeitsweise von einem Server einfach. Die einzigste Aufgabe, die ein Server hat liegt darin, dass er Anfragen entgegen nimmt und beantwortet. Der eigentliche Programmablauf des Servers besteht dabei in einer Endlosschleife, in der der Server eine Anfrage annimmt, irgendwas mit ihr tut und ggf. eine Antwort zurückschickt. Ein Protokoll regelt dabei natürlich wie eine Anfrage und wie die Antworten aussehen. Das Protokoll wäre der Teil, der auf dem TCP-Server aufbaut, hier also erstmal nicht weiter wichtig.

Ok, hoffe die grundsätzliche Arbeitsweise ist klar (die ist wirklich so einfach wie sie hier steht). Jetzt habe ich schon gesagt, dass die Anfragen und Antworten vom verwendeten Protokoll abhängen. Möchtest Du einen Webserver betreiben, wird das Protokoll sicherlich HTTP sein, betreibst Du aber einen FTP-Server, sieht das anders aus. Da die Jungs von Indy hier nicht jeden möglichen Fall abdecken können (Du kannst schließlich selbst ein eigenes Protokoll verwenden), müssen sie einem also die Möglichkeit geben, dass Du festlegst was passiert wenn eine Anfrage eingeht. Um es anders zu sagen, Du musst festlegen was in der Endlosschleife passiert. Dazu wurde die Eigenschaft OnExecute des TIdTcpServers vorgesehen. Diese Eigenschaft ist vom Typ TIdServerThreadEvent (eine Prozedur mit einem Parameter vom Typ TIdContext). Der Parameter AContext gibt dabei einfach (wie der Name schon sagt) den Context an, in dem ein Ereignis gerade stattfindet. Zu diesem Kontext gehört z.B. der Absender der Anfrage, der Empfänger und vieles mehr (die Beiden sind aber erstmal das Wichtigste!). Der Thread wird also in einer Endlosschleife immer diese Prozedur aufrufen und den Code der Prozedur aufrufen. Der Context wird dir automatisch übergeben. Nur wenn diese Eigenschaft zugewiesen wurde, kannst Du den Server starten (er wüßte sonst auch nicht was er tun soll).

Zu den Eigenschaften des AContext gehört unter anderem auch die Connection. Indy verwendet zum Senden von Daten über eine Verbindung das Framework der IOHandler. Ein IOHandler bietet für dich einfache Möglichkeiten Daten zu verschicken. Der eigentlche Vorteil für Dich besteht darin, dass Du viele Details des TCP/IP Kanals nicht zu sehen bekommst. So basiert die Kommunikation bei TCP/IP auf dem verschicken von Paketen. Diese Pakete bestehen wiederum aus deinen Nutzdaten und einer ganzen Menge Metadaten. Die Metadaten beinhalten unter anderen die Adressen von Sender und Absender, aber auch Daten zur Fehlererkennung. Wird ein Paket empfangen, so wird der Empfang bestätigt (ACK). Wird ein Paket empfangen, aber stimmt die Checksumme nicht, so wird eine negative Bestätigung verschickt (NAK). War ein Paket defekt oder wird sein Empfang nicht bestätigt, so wird es automatisch erneut verschickt. All das ist für transparent gekapselt. Auch musst Du dich nicht um die Zerlegung dein Daten in einzelne Pakete kümmern.
Dir stehen durch die IOHandler Methoden wie ReadLn oder WriteLn zur Verfügung. Die Methode Readln liest dabei blockierend einen String aus. Dazu wird auf Pakete mit Nutzdaten gewartet. Die Nutzdaten werden als String interpretiert. Wird hier ein bestimmtes Zeichen gefunden, dass das Ende einer Linie markiert (sollte wohl Carriage Return sein), wird der eingelesene String als Ergebnis der Funktion zurückgegeben. Die Funktion wird dabei erst verlassen, wenn eben dieses Zeichen gelesen wurde (oder ein Fehler, z.B. timeout, eintritt).
Wie jetzt das Lesen genau aussieht kann dem Beispiel entnommen werden, dass ich angehangen habe.

Jetzt sollte schon grob klar sein, wie der Server arbeitet. Sobald man ihn startet, wird er in einer Endlosschleife die übergebene Methode ausführen. In dieser bekommt man einen Kontext, in dem Daten ankommen. Über den Kontext lassen sich Absender und Empfänger bestimmen, sowie die Daten auslesen und verwenden.

Jetzt hatte ich mehrfach erwähnt, dass auch der Empfänger zu dem Kontext gehört. Das mag etwas verwirrend sein, zumal der Server der die Anfrage bekommt sicherlich sich selbst als Empfänger ansehen sollte. Das Problem dabei ist, dass ein Server auf einer Maschine unter ganz unterschiedlichen Adressen erreicht werden kann. So ist jeder Server z.B. über die Loopback Adresse 127.0.0.1 zu erreichen, aber auch jede Netzwerkkarte hat eine eigene Adresse. Verwendet eine Maschine z.B. zwei Netzwerkkarten, die in unterschiedliche Subnetze führen, so kann der Server hier lokale Anfragen (von der 127.0.0.1) und von den beiden Karten jeweils unterschiedlich behandeln wollen. Deswegen ist es wichtig, dass auch die Zieladresse der Anfrage mit übergeben wird.
Die Adresse besteht dabei aus der IP und dem Port. Somit kann ein Server natürlich auch mehr als einen Dienst anbieten, wobei der Dienst dann über IP und Port ermittelt werden kann.

Das ganze findet man dann auch in der Eigenschaft Bindings wieder. Die Bindungen geben die Kombinationen aus IP und Port an, auf denen der Server lauscht. Wie bereits gesagt, ist es durchaus möglich (und teilweise sinnvoll) auf mehr als einem Port und mehr als einer IP zu lauschen. Für diese Fälle kann über die Eigenschaft Bindings für jede Adresse eine eigene Bindung angegeben werden, auf die der Server dann reagiert. Welche dabei angesprochen wurde kann aus dem Kontext der Methode OnExecute ermittelt werden.

Damit sollte grob die komplette Arbeitsweise des Servers klar sein, er bindet Adressen und Ports an sich. Anfragen die auf diesen bebundenen Adresesn ankommen werden in ihrem Kontext an einer Prozedur übergeben. Diese nimmt die Anfragen in einer Endlosschleife entgegen und macht etwas mit ihnen (hängt von der eigenen Implementierung ab).

Auf der anderen Seite steht dann der Client. Dieser verbindet sich gezielt mit einer bestimmten Adresse (an deren Ende ein Server stehen muss). Antwortet kein Server, kommt keine Verbindung zu stande, was zu einem Fehler führt. Wurde eine Antwort empfangen, so kann der Client eine Anfrage abschicken und auf die Antwort durch den Server warten. Ob eine Antwort kommt und was für eine hängt wieder vom Protokoll ab. Im einfachsten Fall sendet der Client nur eine Anfrage ab. Auch dies geschieht über einen IOHandler, der einem diese Arbeit abnimmt.

Ja, ich hoffe dass es Dir etwas weiterhilft. Du hast leider nicht gesagt, welcher Teil der Demos Dir zu komplex war. Solltest Du etwas weiterhin nicht verstehen, frag ruhig gezielter nach (poste den Code den Du nicht verstehst), dann kann man Dir auch gezielter helfen. Anbei noch ein sehr einfaches Beispiel, besteht aus Server und Client. Wichtig ist, dass Du erst den Server startest, dann den Client. Der Client muss auch erst mit dem Server verbunden werden, bevor Du etwas verschickst. Fehler werden (unsauberer Weise) noch gar nicht abgefangen. Alles was Du vom Client aus verschickst, wird in einer ListBox im Server angezeigt.

Gruß Der Unwissende
Angehängte Dateien
Dateityp: zip serverclient_609.zip (18,9 KB, 51x aufgerufen)
  Mit Zitat antworten Zitat
albert1985

Registriert seit: 14. Jan 2007
38 Beiträge
 
Delphi 7 Personal
 
#8

Re: Probleme mit Server-Client-Programmierung (Indy10)

  Alt 28. Jan 2007, 19:01
Wow, da hast du dir aber wirklich Mühe gemacht Vielen Dank !

Also die Probleme die ich oben angesprochen hatte sind jetzt ausgemerzt

Habe es jetzt auch hinbekommen, dass ich vom Client per WriteLn einen String an den Server
schicke und dass dieser wiederrum das ganze verarbeitet (in meinem Fall ein MessageDlg ausgeben).

Da hätte ich auch schon die nächste Frage:
Und zwar, wie kann ich nun vom Clienten aus eine z.B. über ein Edit-Feld eingegebene Nachricht
auf dem Server anzeigen lassen (MessageDlg wie im oberen von mir geposteten Quellcode) ?

Gibts da überhaupt eine Möglichkeit über WriteLn / ReadLn ? Weil
man müsste ja dann quasi einen String, auf den der Server reagieren soll mit einem "beliebigen" String
kombinieren ...
Delphi-Quellcode:
if Line = 'MSG' + beliebiger String then
    MessageDlg('der "Inhalt" des beliebigen Strings',mtInformation,[mbOK],0);
"Was machen Sie? – Wie? Machen? – Ich meine beruflich… – Wieso? Damit Sie Interesse heucheln können?"
  Mit Zitat antworten Zitat
Benutzerbild von inherited
inherited

Registriert seit: 19. Dez 2005
Ort: Rosdorf
2.022 Beiträge
 
Turbo Delphi für Win32
 
#9

Re: Probleme mit Server-Client-Programmierung (Indy10)

  Alt 28. Jan 2007, 19:17
Du kannst entweder ein Command, gefolgt von einem Trennzeichen und dann die Nachricht senden, oder du schickst es einzeln Hintereinander.
Fall eins, Client:
Delphi-Quellcode:
procedure TForm1.NachrichtButtonClick(Sender: TObject);
begin
  if IdTCPClient1.Connected then
  begin
    with IdTCPClient1 do
      IOHandler.WriteLn('MSG:'+Edit1.text);
  end;
end;
Fall eins, Server:
Delphi-Quellcode:
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  Line, Command, Param : String;
begin
  Line := AContext.Connection.IOHandler.ReadLn;
  Command:= Copy(Line, 1, Pos(':', Line)-1);
  Param:= Copy(Line, Pos(':', Line)+1, Length(Line));
  if Command = 'MSGthen
    MessageDlg(Param, mtInformation,[mbOK],0);
end;
Nikolai Wyderka

SWIM SWIM HUNGRY!
Neuer Blog: hier!
  Mit Zitat antworten Zitat
albert1985

Registriert seit: 14. Jan 2007
38 Beiträge
 
Delphi 7 Personal
 
#10

Re: Probleme mit Server-Client-Programmierung (Indy10)

  Alt 28. Jan 2007, 19:53
Sieht elegant aus, deine Lösung Danke !
"Was machen Sie? – Wie? Machen? – Ich meine beruflich… – Wieso? Damit Sie Interesse heucheln können?"
  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 10:59 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