Internet und Netzwerk in Delphi



Vorwort

Es ist unnötig zu sagen, dass dieses Tut nicht den gesamten Bereich der Netzwerk- und Internetprogrammierung in Delphi abdecken kann (wie soll das den auch gehen??). Alles in allem handelt es in diesem Tutorial im Grunde nur über die zwei wichtigsten I-Net-Komponenten in Delphi. Zugegeben: es gibt noch deutlich mehr, aber ich wollte
1) das Tut auch für Newbies überschaubar lassen
2) die Besitzer der Standart-Delphi-Version (oder gar nur der Testversion) nicht benachteiligen, was bei anderen Komponenten der Fall wäre.

Inhalt

Die Winsock-Komponenten
Beispiel1: Der Chat
Beispiel2: Der einfache Portscanner
Downloads



Die Winsock-Komponenten



Dann las uns mal loslegen:
Also: Zunächst muss gesagt sein, dass die zweifellos meist genutzten Internet und Netzwerk Komponenten (für Anfänger: Objekte) in Delphi die Beiden Winsock-Komponenten sind. Diese zwei Komponenten (ServerSocket und Clientsocket) findet man im Register "Internet" der Objektpalette.
Wie der Name schon sagt, ist die eine Komponente für den Server und die andere für den Client der Internetanwendung verantworlich.
Im folgenden sind die wichtigsten Eigenschaften der Beiden Objekte aufgelistet:


ServerSocket
Eigenschaft/Methode Typ Beschreibung
Serversocket1.Port Eigenschaft Hier trägt man den Port ein, auf welchen der ServerSocket komunizieren soll (diese Eigenschaft kann man auch schon im Objektsinspector setzen - muss man aber nicht)
Socket.ActiveConnections Eigenschaft Gibt die Anzahl der verbundenen Clienten wieder (! Nur in der Laufzeit verfügbar/nur lesen!)
Serversocket1.Socket.ReceiveText Eigenschaft Wenn der Server vom Clienten einen Text gesendet bekam, kann man diesen hiermit abrufen. (!Nur in der Laufzeit!/gut kombinierbar mit "onclientread")
ServerSocket1ClientRead (onclientread) Ereigniss Dieses Ereigniss wir ausgelößt, wenn der Client Daten (wie z.b. Texte) an den Server sendet. Diese könnten dann mit ("receivetext" [s.o.]) gelesen werden
ServerSocket1.open Methode Öffnet den Server - der Server ist bereit für eine Verbindung
ServerSocket1.close Methode Schliest den Server wieder (logisch :-) )
ServerSocket1.Socket.
Connections[i].sendtext(Text = String)
Methode Sendet an den Clienten mit der Nummer "i" den in der Klammer eingegebenen String. Achtung: der 1. Client hat die Nummer 0 !!
Damit hätten wir den Server abgehandelt. Es sieht nach einer ganzen Menge aus, ist aber in der Praxis halb so schlimm. Im Grunde ist es sogar sehr einfach - ich habe es nur etwas gewöhnugsbedürftig dargestellt (im Praxisteil nacher, ist das alles ganz einfach). Nun der ClientSocket:


ClientSocket
Eigenschaft/Methode Typ Beschreibung
ClientSocket1.Host Eigenschaft Hier trägt man die IP-Adresse des Servers, mit dem man sich verbinden möchte,ein. (diese Eigenschaft kann man auch schon im Objektsinspector setzen - muss man aber nicht)
ClientSocket1.Port Eigenschaft Hier trägt man den Port ein, auf welchen der ClientSocket sich mit dem Server verbinden soll (diese Eigenschaft kann man auch schon im Objektsinspector setzen - muss man aber nicht)
ClientSocket1.Socket.ReceiveText Eigenschaft Wenn der Server zum Clienten einen Text gesendet hat, kann man diesen hiermit abrufen. (!Nur in der Laufzeit verfügbar!/gut kombinierbar mit "onread")
ClientSocket1Read (onread) Ereigniss Dieses Ereigniss wir ausgelößt, wenn der Client Daten (wie z.b. Texte) von dem Server erhält. Diese Texte könnten dann mit ("receivetext" [s.o.]) gelesen werden
ClientSocket1.open Methode Verbindet den Clienten mit dem Server (oder versucht es wenigstens)
ClientSocket1.close Methode Schliest die Verbindung (langsam wirds langweilig)
ClientSocket1.Socket.sendtext(Text = String) Methode Sendet an den Server den in der Klammer eingegebenen String. (Gähn)




Beispiel1: Der Chat

Habe ich es immernoch nicht geschafft, dass du völlig demoralisiert aufgibst?? (MMNV / *M) Muss ich etwa weiterschreiben??? Naja in der Praxis ist es gar nicht so schlimm, wie es aussieht - wirst schon sehen (Soviel Durchhaltevermögen muss belohnt werden). Also denn:
Wir wollen also nun unseren eigenen kleinen Chat programmieren. Dazu setzen wir auf dem Formular folgende Objekte:

1) 3x Button (Register : Standart).
Die Captions ändern wir zu:
1) "Server"
2) "Client"
3) "Senden"

2) 2x Edit (Register : Standart).

3) 1x Memo (Register : Standart).

4) 1x ServerSocket (Register : Internet).

5) 1x ClientSocket (Register : Internet).

6) 1x Label (Register : Standart) mit der Aufschrift: "Server-IP"

Das ganze könnte nun so aussehen:

Daran nehmen wir nun diese Veränderungen vor:
1) Wir löschen aus allen Edits und dem Memo den Inhalt.

2) Wir setzen über den Objektsinspector die Ports vom Server- und Clientsocket - in meinem Beispiel ist das Port "123". (Man kann natürlich auch nen anderen nehmen, aber es ist zu raten, dass man für beide Komponenten den selben Port nimmt ;-) )

Nun heist es Prozeduren zu schreiben:
Wir beginnen mit dem Button, auf dem "Server" steht. Wir erstellen eine "Onclick"-Prozedur (besser eine Prozedur zu diesem Ereigniss) - siehe "Delphi-Anfängertutorial". Zwischen "begin" und "end" im Quellcodefenster tragen wir nun diese Zeilen Quelltext ein (alles in Blau sind Kommentare) :


form1.Caption := 'Server'; // Daran sieht man, ob man Server ist
ServerSocket1.Open; // Öffnet den Server


Nun ist die Prozedur für den Client-Button fällig:


form1.Caption := 'Client'; // Daran sieht man, ob man Client ist
ClientSocket1.Host := edit2.Text; // Setzt die Ip-Adresse des Servers
ClientSocket1.open; // Verbindet den Clienten

Nun ist der "Senden"-Button an der Reihe:


if form1.caption='Server' then // Ist es ein Server?
begin //begin des Server-Teils
Memo1.lines.add(edit1.text); //fügt den eigenen Text ins Hauptfeld
serversocket1.Socket.Connections[0].SendText(edit1.text); //Sendet an den 1.Clienten (und dem einzigen) die Nachricht aus Edit1
edit1.text := ''; //Lehrt das "Nachrichten-Eingabe-Feld"
end; //Ende des Server-Teils

if form1.caption='Client' then // Ist es ein Client?
begin // begin des Client-Abschnitts
Memo1.lines.add(edit1.text); //fügt den eigenen Text ins Hauptfeld
clientsocket1.Socket.SendText(edit1.text); // Sendet die Nachricht aus "edit1" dem Server
edit1.text := ''; // Lehrt das "Nachrichten-Eingabe-Feld"
end; // Ende des Client-Abschnitts


So, das hätten wir. Aber sind wir denn schon fertig? Nein - was macht denn nun der Server bzw. der Client, wenn er den Text erhält??? Bislang noch gar nicht ... sollten wir ändern. Wir bauen nun also eine "Serversocket1.onclientread"-Prozedur ein (besser eine Prozedur zu diesem Ereigniss) und ergänzen zwischen "Begin" und "End":


memo1.Lines.Add('Client:' + socket.receivetext); //Fügt dem Hauptfeld die Nachricht hinzu

Das ganze nun noch mal für "clientsocket1.onread" :


memo1.Lines.Add('Server:' + socket.receivetext); //Fügt dem Hauptfeld die Nachricht hinzu

Wenn man nun den Chat testet, dürfte das etwa so aussehen:


Ich hätte da noch ne nette Aufgabe: Versuche doch mal, den Chat so umzucoden, dass (Nick-)Names mit angezeigt werden. Viel Erfolg.

Das war nun also das 1. Beispiel - war doch gar nicht so schlimm, wie es am Ende des 1.Kapitels aussah, oder? Naja - jedenfalls werden wir gleich mit dem 2.Beispiel weiter machen - einen einfachen (nicht gerade Komfortablen und sehr langsamen) Portscanner. Viel Spaß...



Beispiel2: Der Portscanner

Noch nicht eingeschlafen? Na den:
Nun kommt also das Kapitel, auf das die Scriptkiddys, Webmaster, Microsoft Bosse und sonstige Verbrecher schon lange gewartet haben - wir programmieren nen eigenen Portscanner!
Also: Wir beginnen wie im letzten Beispiel mit dem Setzen der Komponenten:

1) 1x Button (Register: Standart) Caption = "Start"
2) 1x Edit (Register: Standart)
3) 2x SpinEdit (Register: Beispiele)
4) 1x Client Socket (Register: Internet)
5) 1x List Box (Register: Standart)
6) 4x Label (Register: Standart) Aufschrifen:
1. "IP"
2. "Von Port"
3. "bis Port"
4. "Scannen"


Das sollte dan etwa so angeordnet werden:


Nun müssen wir noch eine besondere Einstellung vornemen:
Wir ändern im Objektsinspector die Eigenschaft "ClientType" des ClientSocket auf "ctBlocking". Dies ist unbedingt nötig, da ansonsten der Portscanner nicht funktionieren dürfe.

Nun kommt der allgemein geliebte Quellcode (wir brauchen in diesem Fall aber nur eine Prozedur!):
Wir legen eine "Button1Onklick"-Prozedur an (einfach doppelt auf den button klichen!).
Zunächst legen wir eine Lokale Variable mit Namen "i" an, die später unsere Zählvariable wird (Variablenerstellung siehe Anfängertutorial). Nun schreiben wir diesen Quellcode zwischen begin und end (Komentare sind Blau):



listbox1.Clear; //Alte Einträge löschen
clientsocket1.Host := edit1.text; //Sagt dem Clientsocket, welcher Host angepingt werden soll
for i := spinedit1.Value to spinedit2.Value do //In einer Schleife dafür sorgen, dass alle zu testenden Ports durchlaufen werden
begin // Begin der Schleife
try //Alles, was nun kommt (bis zu "except"), dient dazu, das der Server angepingt wird. Für den Fall, das der Port "dicht" ist, brauchen wir diesen Resourcen-Schutzblock
clientsocket1.Port := i; // der Port wird gesetzt
clientsocket1.open; //Versuch zu verbinden
clientsocket1.Close; //Sollte man so weit gekommen sein, wird die Verbindung wieder geschlossen
listbox1.Items.add('Port ' + inttostr(i) + ' ist offen'); //Meldung, dass Port offen
application.ProcessMessages; //Messages abarbeiten
except // Alles ab nun wird ausgeführt, wenn die Verbindung fehlschlug
application.ProcessMessages; //Messages abarbeiten
listbox1.Items.add('Port ' + inttostr(i) + ' ist geschlossen'); //Meldung, dass Port zu
end; // Ende den "Try-Bereiches"
end; // Ende der Schleife



Ich denke ich muss Einiges erklären:
1) der try ... ecept - Befehl sorgt dafür, dass im Falle eines Fehlers im Bereich zwischen "Try" und "Except" dieser "Block" abgebrochen wird und dass das, was nach dem "except" steht ausgeführt wird. Bei unserem Portscanner wird nämlich immer dann, wenn ein Port nicht offen ist ein Fehler ausgelößt und es wäre sehr nervig, wenn immer eine Fehlermeldung von Windows erscheinen würde.
2) der Befehl "application.ProcessMessages" bewirkt, dass nun erst mal alle eingegangenen Nachrichten abgearbeitet werden. Dies ist nützlich, da das Scannen von Ports mit diesem Scanner sehr lange dauert und ansonsten das Programm in der Zwischenzeit "festhängen" würde.


Wenn man nun den Portscanner startet, rate ich zu einem:
Beende den Scanner sofort wieder, öffne den Windows-Explorer und starte den Portscanner von hier aus. Dies ist zu raten, da ansonsten der Delphi-Debugger jedesmal, wenn ein Port geschlossen ist, einen Fehler meldet - mit der Explorer-Variante kommt man um dieses Problem herum.


Im Betrieb dürfte der Portscanner etwa so aussehen (IP-Adresse teilweise zensiert!):


Das wars nun mit diesem Internet-Tutorial - ich hoffe es hat gefallen und hat etwas begeistert (ja, du kannst jetzt aufwachen).
Viel Spaß bein Scannen!



Downloads

Dieses Tutorial als RTF-File
Der Chat mit Quellcode
Der Portscanner mit Quellcode



Februar 2002: Mr_T für DCW-Group
mr_t@dcw_group.net / dcw_mr_t@hotmail.com