Tja... Stream ist schon ganz richtig, ich schätze du codest wieder in Delphi (MAN! schreib das dazu)?!
/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\
| GGGGGG CCCCCC FFFFFFF |
| G G C F | | G C FFFF |
| G GGG C FFFF |
| G G C F |
| GGGGGG CCCCCC F |
| |
| [G]erman [C]omputer [F]reaks |
\ Since 1997 /
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Titel: Internet - Anwendungen mit Delphi
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Eine Einführung
I. Vorwort
~~~~~~~
In diesem Tutorial wird beschrieben, wie man unter Delphi mit Hilfe
der Standart Komponenten (Delphi Enterprise/Client Server) Internet-
Anwendungen programmiert.
Meine Art Tuts/faqs/HowTos zu schreiben ist nicht immer ganz normal,
aber ich hoffe mal, dass ihr versteht, was ich meine.
Ich setze voraus, dass ihr euch mit Delphi halbwegs auskennt und wisst,
wie man einen OpenDialog benutzt oder wisst, was eine global deklarierte
Variable ist. Falls nicht, empfehle ich euch auf die Seite
www.pascalpages.de zu gehen und euch dort die Anfänger Tuts zu ziehen.
Bei Fragen: natok@gcf.de
Betreff: Internet - Anwendungen mit Delphi
II. Was brauche ich?
~~~~~~~~~~~~~~~~
Ich gehe mal davon aus, dass ihr mindestens Delphi Client-Server bzw.
Enterprise habt. Kaufen wäre zwar etwas teuer, aber wofür gibts Warez.
( das ist kein Aufruf zum warez tradeing!!!!! )
Dabei sollten folgende Komponenten enthalten sein:
- TClientSocket
- TServerSocket
- NMFTP
- NMSMTP
III. TClient/TServer - Socket
~~~~~~~~~~~~~~~~~~~~~~~~
Bei diesen Komponenten handelt es sich um simple TCP/IP Bausteine.
Die TClientSocket dient zum Aufbau einer Verbindung und kann wie die
TServerSocket Daten empfangen und verschicken. Diese Komponenten bieten
eine einfache Handhabung des TCP/IP Protokolls wie z.B. die Ermittlung
der IP des Remote Hosts.
3.1 Aufbau einer Verbindung
~~~~~~~~~~~~~~~~~~~~~~~
Eine Verbindung mit der TClientSocket herzustellen ist sehr einfach,
solange sie nur den Host ansprechen wollen, und die Verbindung nicht
über einen Proxy laufen lassen. Für das Beispiel nenne ich jetzt
die ClientSocket 'cs' und die ServerSocket 'ss'.
cs.Port:=80; // Festlegung des Ports
cs.Host:=127.0.0.1; // IP des Zielrechners
cs.Active:=true; // Aufbau der Verbindung
Der Port der ClientSocket muss IMMER ein Integer bzw. LongInt sein.
Denken sie daran, dass zuerst der Host und der Port definiert werden
muss, bevor sie die Verbindung aufbauen. Nach dem selben Schema läuft
es auch bei der ServerSocket ab.
ss.Port:=80; // Festlegung des Ports
ss.Active:=true; // Aktivierung der ServerSocket
Wie sie jetzt sehen, wurde keine IP definiert. Das liegt daran, weil
die ServerSocket wie nach dem Namen ein Server ist. d.h. sie wartet
auf Verbindungen.
3.2 Senden und Empfangen
~~~~~~~~~~~~~~~~~~~~
Für den Verkehr zwischen ServerSocket und ClientSocket, greifen wir jetzt
auf "Plain Text" zurück d.h. es wird nur Text versendet.
Hier wird jetzt der Client dem Server den Text 'PING' senden. Der Server
wird den empfangenen Text kontrollieren und darauf antworten.
Dabei kontrolliert der Client zuerst, ob eine Verbindung besteht.
Natürlich muss der Client auch den Text ausgeben, den der Server als
Antwort sendet.
Client
~~~~~~
procedure TForm1.Button1Click(Sender: TObject);
begin
if cs.Socket.Connected=true then // wenn Verbindung besteht,
cs.Socket.SendText('PING'); // dann sende 'PING'
end;
procedure TForm1.csRead(Sender: TObject; Socket: TCustomWinSocket);
var rec:String;
begin
rec:=socket.ReceiveText; // der empfangene Text wird in die Variable 'rec' geschrieben
Memo1.Lines.Add(rec); // Ausgabe der Variable 'rec'
end;
Server
~~~~~~
procedure TForm1.ssClientRead(Sender: TObject; Socket: TCustomWinSocket);
var rec:String;
Begin
rec:=Socket.ReceiveText;
if (rec='PING') then
Socket.SendText('PONG');
end;
Dieses Beispiel lässt sich nur durch den programmierten Client ansprechen
und NICHT durch Telnet, da Telnet jedes Zeichen direkt sendet und dadurch
wird der Server jedes Zeichen interpretieren.
3.3 Anprechen über Telnet
~~~~~~~~~~~~~~~~~~~~~
Um dem Server die Befehle auch per Telnet zukommen zu lassen, muss der Server
auch das Telnet Protokoll unterstützen. Keine Angst, ihr müst jetzt nicht
das RFC zu Telnet lesen, sondern es müssen nur ein paar Zeilen dazugeschrieben
werden, also ganz harmlos.
Wir brauchen also zwei Variablen. Eine um den aktuellen, empfangenen Text zu lesen
und eine, die durch die andere aufgefüllt wird. Das könnte also so aussehen.
wort:=wort+zeichen;
Wir müssen also nur solange das Wort zusammensetzen, bis wir einen Zeilenumbruch
bekommen. Unter Delphi/pascal sieht ein Zeilenumbruch folgendermaßen aus: #13#10
procedure TForm1.ssClientRead(Sender: TObject; Socket: TCustomWinSocket);
var zeichen:String;
begin
Zeichen:=Socket.ReceiveText;
Socket.SendText(zeichen); // echo auf dem Telnet Client
wort:=wort+zeichen;
if (zeichen = #13#10) then
Begin
Delete(wort,Length(wort)-1,Length(wort)); // entfernen des Zeilenumbruchs aus dem String
if (copy(wort,1,4)='PING') then // sichere interpretation des empf. Textes
Begin
Socket.SendText('PONG'+#10#13); // senden der Antwort
Socket.SendText('~>'); // Prompt ermöglichen
end;
end;
end;
Wie ihr nun festgestellt habt, ist die Variable 'wort' überhaupt nicht definiert worden.
Nach diesem Auszug stimmt es auch. Ich hab diese Variable Global definiert und unter
dem Event FormCreate folgendermaßen angegeben: wort:='';
Dies muste ich so machen, da sonst der Text nicht richtig interpretiert werden konnte.
Hier sehen sie auch einige Extras, wie dem Prompt oder dem Entfernen des Zeilenumbruchs.
Diese hab ich noch eingebaut, da es einfach schöner aussieht ;)
Den Zeilenumbruch entferne ich, da man sonst noch eine Schleife und eine copy funktion
benutzen muss.
Denken sie daran, dass folgendermaßen bei dieser version geantwortet werden muss:
Socket.SendText('PONG'+#10#13);
Das #10#13 muss angehangen werden, da sonst der Client keinen Zeilenumbruch erhält.
Bei dem Prompt fällt dies natürlich wieder weg.
3.4 Tips & Tricks
~~~~~~~~~~~~~
Hier biete ich jetzt auch mal noch einen Auszug aus einem meiner Programme.
Dieses Programm besteht eigentlich nur aus einer ServerSocket. Es handelt sich
um ein Programm, dass den NetBus Port 12345 offen hält und auf eine Verbindung
wartet. Wenn es eine bekommt, dann stellt das Programm die IP des Clients da
und trennt die Verbindung. Hier bietet Borland eine kleine Funktion um diese
zu ermitteln:
ServerSocket.Socket.RemoteAddress;
Bei dem Rückgabewert handelt es sich um einen String. Nun aber der komplette
Quelltext:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ScktComp, StdCtrls, ComCtrls;
type
TForm1 = class(TForm)
GroupBox1: TGroupBox;
GroupBox2: TGroupBox;
Memo1: TRichEdit;
Button1: TButton;
Button2: TButton;
ss: TServerSocket;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure ssClientError(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
procedure ssClientConnect(Sender: TObject; Socket: TCustomWinSocket);
procedure ssClientRead(Sender: TObject; Socket: TCustomWinSocket);
procedure ssClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
VAR
Form1: TForm1;
test:Boolean = false;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
ss.Active:=true; // der port ist schon om Objektinspector vordefiniert
Button2.Enabled:=true;
Button1.Enabled:=false;
Memo1.Lines.Add('['+TimeToStr(Time)+'] Listen...');
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
ss.Active:=false;
Button2.Enabled:=false;
Button1.Enabled:=true;
Memo1.Lines.Add('['+TimeToStr(Time)+'] Stop...');
end;
procedure TForm1.ssClientError(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
errorcode:=0;
end;
procedure TForm1.ssClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
var from:String;
begin
from:=Socket.RemoteAddress; // zwischenspeichern der IP
Memo1.Lines.Add('['+TimeToStr(Time)+']: Connection from '+from);
socket.SendText('NetBus 1.60'+#10#13);
end;
procedure TForm1.ssClientRead(Sender: TObject; Socket: TCustomWinSocket);
begin
Memo1.Lines.Add('Receive Text: '+socket.ReceiveText); // empfangenen Text wiedergeben
end;
procedure TForm1.ssClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Memo1.Lines.Add('Disconnect');
end;
end.
IV. NMFTP
~~~~~
Hier handelt es sich um die standart Komponente von Borland/Inprise, die die
Funktionen eines FTP - Clients ermöglicht. Dadurch, dass sie sehr viele
Events hat, is eine einfache Fehlermeldungendarstellung möglich.
4.1 Aufbau einer Verbindung
~~~~~~~~~~~~~~~~~~~~~~~
Im Vergleich zu der ClientSocket hat sich hier relativ wenig verändert;
es ist aber durch eine einfache Schleife möglich einen FTP Proxy zu
verwenden. Für die Beispiele nenne ich die NMFTP Komponente nun 'ftp'.
If CheckBox1.Checked then // wenn ein Proxy verwendet werden soll,
Begin
ftp.Proxy :=my_proxy; // dann ist der String my_proxy der Proxy
ftp.ProxyPort := proxy_port; // und der Integer proxy_port sein Port
end;
ftp.Host := 'ftp.microsoft.com' // Festlegung des Hosts
ftp.Port := 21; // Festlegung des Ports (STANDART PORT)
ftp.Timeout := 5000; // TimeOut
ftp.UserID := 'anonymous'; // Benutzername, hier anonymous ftp
ftp.Password :='billgates@microsoft.com'; // das Passwort
ftp.Connect; // aufbau der Verbindung
In diesem Beipiel versuchen wir uns auf den FTP Server von Microsoft über
anonymous FTP einzuloggen. (s. FTP-Hacking)
Der Port 21 ist der Standart Port von dem FTP Service. Da mir kein FTP Proxy
bekannt ist, hab ich diesem und dem Port einfach Variablen zugewiesen.
Der Host ist ein String und der Port ein Integer Wert.
4.2 Befehle des Clients
~~~~~~~~~~~~~~~~~~~
In dieser Richtung ist uns Borland sehr entgegenkommend. Wir brauchen eigentlich
nur Variablen in den Befehl einzubauen und es ist erledigt. Deshalb liste ich jetzt
hier die gängigen FTP Befehle auf, die ein Client braucht.
|Aktion |Befehl |Kommentar |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|Disconnect | ftp.Disconnect; | (Verbindung trennen) |
|Connect | ftp.connect; | (Verbindung herstellen) |
|List | ftp.List; | (OnListEvent beachten) |
|Chg Directory | ftp.ChangeDir(dir:String); | (Verzeichnis wechseln); |
|Download | ftp.Download(remotef, Localf); | (beide Namen sind Strings) |
|Abort | ftp.Abort; | (Abbrechen) |
|Restore | ftp.DownloadRestore(remotef,Localf); | (Wiederherstellen des Downloads) |
|Upload | ftp.Upload(localf, remotef); | (Hochladen einer Datei); |
|Append | ftp.UploadAppend(localf, remotef); | (Append) |
|MkDir | ftp.MakeDirectory(dir:String); | (Verzeichnis erstellen) |
|RmDir | ftp.RemoveDir(dir:String); | (Verzeichnis entfernen) |
|Rename | ftp.Rename(from,to:String); | (umbenennen von 'from' nach 'to') |
|Delete | ftp.Delete(remotef:String); | (Datei löschen) |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Weitere Befehle sind aus der Delphi Hilfe zu entnehmen.
V. NMSMTP
~~~~~~
Bei dieser Komponente handelt es sich auch um eine standart Komponente, die in
Delphi enthalten ist. Diese dient als SMTP - Client und ermöglicht die einfache
Verwendung des SMTP Protokolls. Der Nachteil an dieser Komponente ist, dass
standartmäßig alle Events eine Fehlermeldung ausgeben. Um das zu verhindern, muss
man die einzelnen Fehler nach Zahlencodes abfangen.
5.1 Aufbau einer Verbindung
~~~~~~~~~~~~~~~~~~~~~~~
Der Aufbau der Verbindung läuft nach dem gleichen Schema wie die vorherigen
Verbindungsaufbaue ab ;) Ich benenne die NMSMTP Komponente in smtp um.
smtp.Host := 'post.strato.de'; // der Host ;)
smtp.Port := 25; // der SMTP POrt (Standart)
smtp.UserID := Edit4.Text; // Nana, hier gebe ich doch kein Beispiel ;)
smtp.Connect; // und da is der Befehl zum Verbindungsaufbau
In diesem Beispiel verbinden wir uns zu dem Strato SMTP Server auf Port 25. Bei dem Host handelt
sich um einen String, man kann aber auch eine IP eintragen. Der Port ist in der Regel 25, könnte
aber theoretisch variieren ;)
Bei der UserID wird die Benutzerkennung übertragen, bei einem anonymous server ist diese aber
unnötig, da wir ja keinen Account besitzen.
5.2 Eine Mail verschicken
~~~~~~~~~~~~~~~~~~~~~
Wir haben nun eine Verbindung (oder?) zu einem SMTP Server. Nun wollen wir aber eine
Mail verschicken. Die NMSMTP Komponente ist bei den Einstellungen sehr komfortabel.
Wir haben die Möglichkeit uns einen Header selbst zusammenzubauen und andere diverse
Einstellungen vorzunehmen wie z.B. Charset, plaintext oder html, usw.
In diesem Beispiel zeige ich aber nur, wie man eine plain Text Mail verschickt. Die
restlichen Einstellungen sind im Objectinspector einsehbar.
smtp.PostMessage.FromAddress :='root@microsoft.com'; // Absender Adresse
smtp.PostMessage.FromName :='scheiß admin'; // Name des Absenders
smtp.PostMessage.Subject :='Kündigung'; // Betreff
smtp.PostMessage.ToAddress.Add('bill@microsoft.com'); // Empfänger Adresse
smtp.PostMessage.ToBlindCarbonCopy.Add('Clinton@withehouse.gov'); // BCC
smtp.PostMessage.ToCarbonCopy.Add('waswei@ich.de'); // CC
smtp.PostMessage.Attachments.AddStrings(Listbox1.Items); // Dateien aus Liste übertragen
smtp.PostMessage.Body.Assign(Memo1.Lines); // Nachricht wird aus textfeld genommen
smtp.SendMail; // verschicken der Mail
Hier gibts nun nichts mehr zu sagen, da ich mal denke, wenn man den rest sorgfältig durchgelesen
hat, dass man das hier versteht. Falls nicht, oben steht meine Mail Adresse ;)
VI. Ende/Nachwort/Greets
~~~~~~~~~~~~~~~~~~~~
Ich hoffe, dass Newbies mit diesem Tutorial geholfen wurde. Alles Protokolle zu
erwähnen, wäre wohl etwas viel, deshalb hab ichs auf das Nötigste begrenzt.
Es gibt keine deutschen Bücher über dieses Thema, und ich hatte auch nicht vor eins
zu schreiben ;) ; vielleicht werde ich noch eine Fortsetzung schreiben über
die anderen Protokolle.
THX to:
Deeptroat, Du-Ne, Insider, Busch-Hacker, und natürlich alle anderen Groups.
*****************
*Natok aka OMEGA*
*natok@gcf.de *
*UIN: 44163428 *
*****************
Hab ich mal im Netz gefunden... dürfte dir genug Grundlagen bieten...
--shielding people from their own stupidity is an evolutionary step backwards anyway.