Programmieren von Sockets in Delphi. Server

19.08.2023

In diesem Artikel werden die grundlegenden Eigenschaften und Funktionen der Delphi-Komponenten TClientSocket und TServerSocket erläutert, die für die Arbeit mit dem Netzwerk unter Verwendung des TCP\IP-Protokolls verwendet werden.

Aufmerksamkeit! Wenn Sie eine höhere Delphi-Version als 6.0 verwenden, müssen Sie zunächst Sockets Components installieren; in allen Delphi-Versionen geschieht dies wie folgt:

  • Gehen Sie zum Dialogfeld „Pakete installieren...“: (Hauptmenü) Komponente -> Pakete installieren;
  • Klicken Sie auf die Schaltfläche „Hinzufügen…“, woraufhin wir den Bin-Ordner Ihres Delphi finden (zum Beispiel: C:\Programme\Borland\Delphi 7\bin oder C:\Programme\Embarcadero\RAD Studio\7.0\Bin). ;
  • Im gefundenen Bin-Ordner suchen wir bereits nach der Datei dclsockets [hier sind die Zahlen].bpl, OK klicken;
  • Wir freuen uns, denn jetzt haben wir zwei wunderbare Komponenten, TServerSocket und TClientSocket, auf der Registerkarte „Internet“ des Komponentenfensters.

Bei der Entwicklung von Netzwerkanwendungen beginnt die Entwicklung normalerweise immer mit dem Server (wenn Sie ein Team haben, können Schnittstellendesigner natürlich mit der Arbeit am Client beginnen). Um einen Server zu implementieren, müssen Sie überraschenderweise TServerSocket verwenden.

Grundeigenschaften:

  • Aktiv– ein boolesches Feld, wenn es auf true gesetzt ist – der Server startet, Sie können es entweder durch die Zuweisung bestimmter Werte oder durch den Aufruf der Funktionen ServerSocket1.Open (... Active:=true;) oder ServerSocket1.Close (..) verwenden. . Aktiv:=false).
  • Hafen– der Port, an dem der Server lauscht (Clients empfängt), jeder Wert innerhalb des Bereichs, der nicht von anderen Servern im System belegt ist ganze Zahl.

Hauptveranstaltungen:

  • OnListen– wird aufgerufen, wenn der Server auf den Abhörmodus eingestellt ist, kann verwendet werden, wenn wir den Zeitpunkt des tatsächlichen Starts des Servers bestimmen müssen.
  • OnClientRead– wird aufgerufen, wenn Daten vom Client empfangen werden.
  • OnClientError
  • OnClientConnect– Wird aufgerufen, wenn ein neuer Client dem Server beitritt.
  • OnClientDisconnect– Ereignis für Ereignis umkehren, OnClientConnect

Jede Ereignisfunktion hat ein Attribut Socket: TCustomWinSocket, es wird ein Zeiger auf das Socket-Objekt übergeben, mit dem wir gerade arbeiten. Wenn wir mit dem Client, der das Ereignis verursacht hat, antworten oder etwas mit ihm tun müssen, müssen wir dieses bestimmte Objekt verwenden, in allen anderen Fällen verwenden wir es ServerSocket1.SocketÄhnlich verhält es sich mit der Client-Komponente.

Schreibgeschützte Eigenschaften und Funktionen:

  • – gibt die Anzahl der aktiven Verbindungen zurück.
  • ServerSocket1.Socket.Connections– ein Array von Objekten vom Typ TCustomWinSocket, ein Array aller mit Clients verknüpften Objekte, die Indexzählung beginnt bei 0, die Länge des Arrays beträgt ServerSocket1.Socket.ActiveConnections.
  • Funktionen und Eigenschaften, die auf die Elemente des ServerSocket1.Socket.Connections-Arrays und das Socket-Attribut angewendet werden, das an die Serverereignisfunktion übergeben wird:
  • Socket.LocalHost
  • Socket.LocalAddress– gibt die Server-IP zurück.
  • Socket.RemoteHost
  • Socket.RemoteAddress– gibt die Client-IP zurück.
  • Socket.ReceiveText– gibt eine vom Client empfangene Textnachricht zurück und löscht anschließend den Puffer. Kann nur einmal pro Empfang verwendet werden.
  • Socket.SendText(Text)– sendet eine Textnachricht vom Typ Text an den Client Zeichenfolge.

Für die TClientSocket-Komponente ist praktisch alles gleich, nur umgekehrt + der wesentliche visuelle Unterschied zwischen dem Server und dem Client besteht darin, dass der Server im System 1 mal 1 Portwert gestartet werden kann, die Anzahl der Clients ist nur durch den RAM begrenzt .

Grundeigenschaften:

  • Aktiv– ein boolesches Feld, wenn es auf true gesetzt ist – der Client versucht, eine Verbindung zum Server herzustellen, kann entweder durch Zuweisung bestimmter Werte oder durch Aufrufen der Funktionen ClientSocket1.Open (... Active:=true;) oder ClientSocket1 verwendet werden .Schließen (... Active:=false) .
  • Hafen– Port, über den der Client eine Verbindung zum Server herstellen kann, jeder Wert innerhalb des Bereichs ganze Zahl.
  • Adresse– IPv4-Adresse des Servertyps Zeichenfolge nach dem Muster 255.255.255.255, mit dem sich der Client verbindet.

Hauptveranstaltungen:

  • OnRead– wird aufgerufen, wenn Daten aus dem Norden empfangen werden.
  • OnError– wird aufgerufen, wenn bei der Datenübertragung ein Fehler auftritt.
  • OnConnecting– Wird aufgerufen, wenn ein Client dem Server beitritt.
  • OnDisconnect– Ereignis für Ereignis umkehren, OnConnecting, wird aufgerufen, wenn ein Client die Verbindung zum Server trennt.

Schreibgeschützte Eigenschaften und Funktionen:

  • ClientSocket1.Socket.SendText() Zeichenfolge
  • Socket.LocalHost– gibt den Online-Namen des Kunden zurück.
  • Socket.LocalAddress– gibt die Client-IP zurück.
  • Socket.RemoteHost– gibt den Namen des Servers im Netzwerk zurück.
  • Socket.RemoteAddress– gibt die Server-IP zurück.
  • Socket.ReceiveText– gibt eine vom Server empfangene Textnachricht zurück und löscht anschließend den Puffer. Kann jeweils nur einmal verwendet werden.
  • Socket.SendText(Text)– sendet eine Textnachricht vom Typ Text an den Server Zeichenfolge.

Die bereitgestellten Informationen reichen völlig aus, um einen kleinen Server-Chat zu implementieren, der den technischen Spezifikationen entspricht: internet_sockets.doc (Word Doc 97-2003, 26,5 Kb).

Dieser Artikel wurde am Sonntag, 10. Oktober 2010 um 01:24 Uhr in der Rubrik geschrieben. Sie können Updates zu Kommentaren zum Artikel abonnieren -. Sie können

Einführung

Dieser Artikel widmet sich der Erstellung von Client/Server-Architekturanwendungen in Borland Delphi basierend auf Sockets („Sockets“ - Nester). Im Gegensatz zum vorherigen Artikel zum Thema Sockets befassen wir uns hier mit der Erstellung von Serveranwendungen.

Es sollte sofort darauf hingewiesen werden, dass für die Koexistenz separater Client- und Serveranwendungen nicht mehrere Computer erforderlich sind. Es reicht aus, nur einen zu haben, auf dem Sie gleichzeitig den Server und den Client ausführen können. In diesem Fall müssen Sie den Hostnamen als Namen des Computers verwenden, zu dem Sie eine Verbindung herstellen möchten localhost oder IP-Adresse - 127.0.0.1 .

Beginnen wir also mit der Theorie. Wenn Sie ein überzeugter Praktiker sind (und mit Ihren Augen keine Algorithmen erkennen können), dann sollten Sie diesen Abschnitt überspringen.

Algorithmus für den Betrieb des Socket-Servers

Was ermöglicht Ihnen ein Socket-Server? Nach welchem ​​Prinzip funktioniert er? Ein Server, der auf dem Socket-Protokoll basiert, ermöglicht es Ihnen, viele Clients gleichzeitig zu bedienen. Darüber hinaus können Sie die Begrenzung ihrer Anzahl selbst festlegen (oder diese Begrenzung ganz aufheben, wie es standardmäßig der Fall ist). Für jeden verbundenen Client öffnet der Server einen separaten Socket, über den Sie Daten mit dem Client austauschen können. Eine weitere tolle Lösung besteht darin, für jede Verbindung einen separaten Prozess (Thread) zu erstellen.

Schauen wir uns das Diagramm genauer an:

  • Definition der Port- und ServerType-Eigenschaften - Damit sich Clients normal mit dem Server verbinden können, ist es notwendig, dass der vom Server verwendete Port genau mit dem vom Client verwendeten Port übereinstimmt (und umgekehrt). Die ServerType-Eigenschaft bestimmt den Verbindungstyp (weitere Einzelheiten siehe unten);
  • Einen Socket öffnen - Öffnen des Sockets und des angegebenen Ports. Hier beginnen wir automatisch damit, darauf zu warten, dass Clients eine Verbindung herstellen ( Hören);
  • Einen Client verbinden und Daten mit ihm austauschen - hier verbindet sich der Client mit ihm und tauscht Daten mit ihm aus. Mehr zu dieser Phase erfahren Sie weiter unten in diesem Artikel und im Artikel über Sockets (Client-Teil);
  • Einen Client deaktivieren - Hier trennt der Client die Verbindung und seine Socket-Verbindung zum Server wird geschlossen;
  • Schließen des Servers und des Sockets - Auf Befehl des Administrators fährt der Server herunter, schließt alle offenen Socket-Kanäle und wartet nicht mehr auf Client-Verbindungen.

Es ist zu beachten, dass die Punkte 3-4 viele Male wiederholt werden, d.h. Diese Schritte werden für jede neue Clientverbindung durchgeführt.

Notiz : Derzeit gibt es in Delphi nur sehr wenig Dokumentation zu Sockets. Wenn Sie sich also so tief wie möglich mit diesem Thema befassen möchten, empfehle ich Ihnen, sich die dortige Literatur und elektronische Dokumentation zu Unix/Linux-Systemen anzusehen Sehr Die Theorie der Arbeit mit Sockets ist gut beschrieben. Darüber hinaus gibt es viele Beispiele für Socket-Anwendungen für diese Betriebssysteme (allerdings hauptsächlich in C/C++ und Perl).

Kurze Beschreibung der TServerSocket-Komponente

Hier werden wir uns kennenlernen hauptsächlich Eigenschaften, Methoden und Ereignisse einer Komponente TServerSocket.

Eigenschaften Methoden Veranstaltungen
Steckdose - die TServerWinSocket-Klasse, über die Sie Zugriff auf offene Socket-Kanäle haben. Als nächstes werden wir diese Eigenschaft genauer betrachten, weil es ist tatsächlich eines der wichtigsten. Typ: TServerWinSocket ;
Server Typ - Server Typ. Kann einen von zwei Werten annehmen: stNonBlocking- Synchrones Arbeiten mit Client-Sockets. Mit diesem Servertyp können Sie über Ereignisse mit Clients arbeiten OnClientRead Und OnClientWrite. stThreadBlocking- asynchroner Typ. Für jeden Client-Socket-Kanal wird ein separater Prozess (Thread) erstellt. Typ: TServerType ;
ThreadCacheSize – die Anzahl der Client-Prozesse (Thread), die vom Server zwischengespeichert werden. Hier müssen Sie den Durchschnittswert abhängig von der Auslastung Ihres Servers auswählen. Das Caching erfolgt, um nicht jedes Mal einen separaten Prozess zu erstellen und geschlossene Sockets nicht zu zerstören, sondern um sie für eine spätere Verwendung aufzubewahren. Typ: Ganze Zahl ;
Aktiv - ein Indikator dafür, ob der Server zu einem bestimmten Zeitpunkt aktiv ist oder nicht. Das ist tatsächlich der Wert WAHR zeigt an, dass der Server läuft und bereit ist, Clients zu empfangen, und FALSCH- Der Server ist ausgeschaltet. Um den Server zu starten, müssen Sie diese Eigenschaft lediglich auf setzen WAHR. Typ: Boolescher Wert ;
Hafen - Portnummer zum Aufbau von Verbindungen mit Clients. Die Server- und Client-Ports müssen identisch sein. Empfohlen werden Werte von 1025 bis 65535, denn von 1 bis 1024 - kann vom System belegt werden. Typ: Ganze Zahl ;
Service – eine Zeichenfolge, die den Dienst definiert ( ftp, http, Pop usw.), dessen Port verwendet werden soll. Dabei handelt es sich um eine Art Verzeichnis von Portnummern, die verschiedenen Standardprotokollen entsprechen. Typ: Zeichenfolge ;
Offen - Startet den Server. Im Wesentlichen ist dieser Befehl identisch mit der Zuweisung eines Werts WAHR Eigentum Aktiv;
Schließen - Stoppt den Server. Im Wesentlichen ist dieser Befehl identisch mit der Zuweisung eines Werts FALSCH Eigentum Aktiv.
OnClientConnect – tritt auf, wenn der Client eine Socket-Verbindung hergestellt hat und auf eine Antwort vom Server wartet ( OnAccept);
OnClientDisconnect – Tritt auf, wenn der Client die Verbindung zum Socket-Kanal getrennt hat;
OnClientError – tritt auf, wenn der aktuelle Vorgang fehlschlägt, d. h. Ein Fehler ist aufgetreten;
OnClientRead – tritt auf, wenn der Client einige Daten an den Server übergeben hat. Auf diese Daten kann über den passable Parameter zugegriffen werden Socket: TCustomWinSocket;
OnClientWrite – tritt auf, wenn der Server Daten über einen Socket an den Client senden kann;
OnGetSocket - Im Handler dieses Ereignisses können Sie den Parameter bearbeiten ClientSocket;
OnGetThread - Im Handler dieses Ereignisses können Sie durch Zuweisung des Parameters einen eindeutigen Prozess (Thread) für jeden einzelnen Client-Kanal definieren SocketThread die gewünschte Unteraufgabe TServerClientThread;
OnThreadStart , OnThreadEnd – tritt auf, wenn eine Unteraufgabe (Prozess, Thread) gestartet bzw. gestoppt wird;
OnAccept - tritt auf, wenn der Server den Client akzeptiert oder ihm eine Verbindung verweigert;
OnListen – Tritt auf, wenn der Server in den Wartemodus wechselt, bis Clients eine Verbindung herstellen.

TServerSocket.Socket(TSServerWinSocket)

Wie kann der Server Daten an den Client senden? Wie sieht es mit dem Empfang von Daten aus? Vor allem, wenn Sie Ereignisse durcharbeiten OnClientRead Und OnClientWrite, dann können Sie über den ClientSocket-Parameter (TCustomWinSocket) mit dem Client kommunizieren. Über die Arbeit mit dieser Klasse können Sie im Artikel über Client-Sockets nachlesen, denn Das Senden/Senden von Daten über diese Klasse ist ähnlich – Methoden (Senden/Empfangen)(Text,Puffer,Stream). Gleiches gilt für die Arbeit mit TServerSocket.Socket. Allerdings, weil Da wir über einen Server nachdenken, sollten wir einige nützliche Eigenschaften und Methoden hervorheben:

  • ActiveConnections (Ganze Zahl) - Anzahl der verbundenen Clients;
  • ActiveThreads (Ganze Zahl) - Anzahl der laufenden Prozesse; Verbindungen (Array) – ein Array bestehend aus separaten TClientWinSocket-Klassen für jeden verbundenen Client. Zum Beispiel dieser Befehl:
    ServerSocket1.Socket.Connections.SendText("Hallo!");
    sendet eine „Hallo!“-Nachricht an den ersten verbundenen Client. Befehle zum Arbeiten mit Elementen dieses Arrays – auch (Send/Receive)(Text,Buffer, Stream);
  • IdleThreads (Ganze Zahl) – die Anzahl der freien Prozesse. Solche Prozesse werden vom Server zwischengespeichert (siehe ThreadCacheSize);
  • Lokale Adresse, LocalHost, LocalPort- bzw. lokale IP-Adresse, Hostname, Port;
  • RemoteAddress, Remote-Host, RemotePort- bzw. - Remote-IP-Adresse, Hostname, Port;
  • Methoden Sperren Und Freischalten- Blockieren bzw. Entsperren des Sockets.

Praxis und Beispiele

Schauen wir uns das Obige nun anhand eines konkreten Beispiels an. Sie können vorgefertigte Quellen herunterladen, indem Sie auf klicken.

Schauen wir uns also ein sehr gutes Beispiel für die Arbeit mit TServerSocket an (dieses Beispiel ist die anschaulichste Hilfe zum Studium dieser Komponente). Die folgenden Quellen demonstrieren die Protokollierung aller wichtigen Serverereignisse sowie die Möglichkeit, Textnachrichten zu empfangen und zu senden:

Beispiel 1. Protokollierung und Untersuchung des Serverbetriebs, Senden/Empfangen von Nachrichten über Sockets.

(...Hier geht es zum Dateiheader und zur Definition des Formulars TForm1 und seiner Instanz Form1) (Siehe vollständige Quelle) procedure TForm1.Button1Click(Sender: TObject); beginnen (Bestimmen Sie den Port und starten Sie den Server) ServerSocket1.Port:= 1025; (Die Insert-Methode fügt an der angegebenen Position eine Zeichenfolge in das Array ein.) Memo2.Lines.Insert(0,"Server startet"); ServerSocket1.Open; Ende; procedure TForm1.Button2Click(Sender: TObject); beginnen (Stoppen Sie den Server) ServerSocket1.Active:= False; Memo2.Lines.Insert(0,"Server gestoppt"); Ende; procedure TForm1.ServerSocket1Listen(Sender: TObject; Socket: TCustomWinSocket); beginnen (Hier „lauscht“ der Server am Socket auf Clients) Memo2.Lines.Insert(0,"Listening on port "+IntToStr(ServerSocket1.Port)); Ende; procedure TForm1.ServerSocket1Accept(Sender: TObject; Socket: TCustomWinSocket); beginnen (Hier akzeptiert der Server den Client) Memo2.Lines.Insert(0,"Client-Verbindung akzeptiert"); Ende; procedure TForm1.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket); beginnen (Hier verbindet sich der Client) Memo2.Lines.Insert(0,"Client verbunden"); Ende; procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); beginnen (Hier trennt der Client die Verbindung) Memo2.Lines.Insert(0,"Client getrennt"); Ende; procedure TForm1.ServerSocket1ClientError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); beginnen (Es ist ein Fehler aufgetreten – Code anzeigen) Memo2.Lines.Insert(0,"Client error. Code = "+IntToStr(ErrorCode)); Ende; procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); beginnen (Eine Nachricht wurde vom Client empfangen – zeigen Sie sie in Memo1 an) Memo2.Lines.Insert(0,"Nachricht vom Client erhalten"); Memo1.Lines.Insert(0,"> "+Socket.ReceiveText); Ende; procedure TForm1.ServerSocket1ClientWrite(Sender: TObject; Socket: TCustomWinSocket); beginnen (Jetzt können Sie Daten an den Socket senden) Memo2.Lines.Insert(0,"Jetzt kann in den Socket geschrieben werden"); Ende; procedure TForm1.ServerSocket1GetSocket(Sender: TObject; Socket: Integer; var ClientSocket: TServerClientWinSocket); begin Memo2.Lines.Insert(0,"Get socket"); Ende; procedure TForm1.ServerSocket1GetThread(Sender: TObject; ClientSocket: TServerClientWinSocket; var SocketThread: TServerClientThread); begin Memo2.Lines.Insert(0,"Get Thread"); Ende; procedure TForm1.ServerSocket1ThreadEnd(Sender: TObject; Thread: TServerClientThread); begin Memo2.Lines.Insert(0,"Thread end"); Ende; procedure TForm1.ServerSocket1ThreadStart(Sender: TObject; Thread: TServerClientThread); begin Memo2.Lines.Insert(0,"Thread start"); Ende; procedure TForm1.Button3Click(Sender: TObject); var i: Ganzzahl; beginnen (Senden Sie eine Nachricht an ALLE Kunden von Edit1) for i:= 0 to ServerSocket1.Socket.ActiveConnections-1 do begin ServerSocket1.Socket.Connections[i].SendText(Edit1.Text); Ende; Memo1.Lines.Insert(0,"< "+Edit1.Text); end;

Techniken zum Arbeiten mit TServerSocket (und einfach mit Sockets)

Speicherung einzigartiger Daten für jeden Kunden.

Wenn Ihr Server viele Clients bedienen wird, müssen Sie sicherlich einige Informationen für jeden Client speichern (Name usw.) und diese Informationen an den Socket dieses Clients binden. In einigen Fällen ist es nicht sehr praktisch, dies alles manuell durchzuführen (Bindung an ein Socket-Handle, Client-Arrays usw.). Daher gibt es für jeden Socket eine spezielle Eigenschaft - Daten. Tatsächlich sind Daten nur ein Hinweis. Seien Sie daher beim Schreiben von Client-Daten in diese Eigenschaft vorsichtig und befolgen Sie die Regeln für die Arbeit mit Zeigern (Speicherzuweisung, Typdefinition usw.)!

Senden von Dateien über Socket.

Hier schauen wir uns das Senden von Dateien über einen Socket an (auf Wunsch von JINX) :-). Wie sendet man also eine Datei über einen Socket? Sehr einfach! Sie müssen diese Datei lediglich als Dateistream öffnen (TFileStream) und über einen Socket senden (SendStream)! Schauen wir uns das anhand eines Beispiels an:

Es ist zu beachten, dass die Methode SendStream Wird nicht nur vom Server, sondern auch vom Client verwendet ( ClientSocket1.Socket.SendStream(srcfile))

Warum können bei der Übertragung mehrere Blöcke zu einem zusammengefasst werden?

Dies geschieht auch auf Wunsch von JINX :-). Vielen Dank dafür! Zunächst ist also zu beachten, dass über einen Socket versendete Daten nicht nur zu einem Block zusammengefasst, sondern auch auf mehrere Blöcke aufgeteilt werden können. Tatsache ist, dass ein Socket ein normaler Stream ist, aber im Gegensatz zu beispielsweise einem Dateistream (TFileStream) Daten langsamer überträgt (Sie verstehen - Netzwerk, begrenzter Datenverkehr usw.). Deshalb zwei Befehle:
ServerSocket1.Socket.Connections.SendText("Hallo, ");
ServerSocket1.Socket.Connections.SendText("world!");
völlig identisch mit einem Befehl:
ServerSocket1.Socket.Connections.SendText("Hallo, Welt!");

Wenn Sie also eine Datei von beispielsweise 100 KB über einen Socket senden, erhält die Person, an die Sie diesen Block gesendet haben, mehrere Blöcke, deren Größe vom Datenverkehr und der Leitungsüberlastung abhängt. Darüber hinaus werden die Größen nicht unbedingt gleich sein. Daraus folgt, dass Sie zum Akzeptieren einer Datei oder einer anderen großen Datenmenge Datenblöcke akzeptieren und diese dann zu einem Ganzen kombinieren (und beispielsweise in einer Datei speichern) sollten. Eine hervorragende Lösung für dieses Problem ist der gleiche Dateistream – TFileStream (oder ein Stream im Speicher – TMemoryStream). Mit der universellen Methode können Sie über das Ereignis OnRead (OnClientRead) Daten von einem Socket empfangen EmpfangsBuf. Mit der Methode können Sie die Größe des resultierenden Blocks bestimmen Empfangslänge. Sie können auch einen Socket-Stream verwenden (siehe Artikel über TClientSocket). Und hier ist ein kleines Beispiel (ungefähr):

So überwachen Sie eine Steckdose

Dieses Problem ist komplex und erfordert eine lange Überlegung. Vorerst möchte ich nur anmerken, dass Sie den von Ihrem Programm erstellten Socket jederzeit überwachen können :-). Sockets haben (wie die meisten Objekte in Windows) ihr eigenes Handle, das in die Handle-Eigenschaft geschrieben wird. Sobald Sie diesen Deskriptor kennen, können Sie jeden Socket (auch einen, der von einem anderen Programm erstellt wurde) frei verwalten! Um jedoch den Socket einer anderen Person zu überwachen, müssen Sie höchstwahrscheinlich ausschließlich die WinAPI-Sockets-Funktionen verwenden.

Epilog

Dieser Artikel zeigt die grundlegenden Techniken für die Arbeit mit der TServerSocket-Komponente in Delphi und mehrere allgemeine Techniken für den Datenaustausch über Sockets. Wenn Sie Fragen haben, senden Sie mir diese per E-Mail: [email protected] Und noch besser: Schreiben Sie in die Konferenz dieser Site (Delphi. Allgemeine Fragen), damit andere Benutzer Ihre Frage sehen und versuchen können, sie zu beantworten!

Karikh Nikolay ( Nitro). Region Moskau, Schukowski

Ich habe Netzwerkunterstützung hinzugefügt. Das heißt, er hat einen separaten Server und einen separaten Client erstellt. Die Idee ist, dass der Anwendungsserver läuft, der Benutzer den Client startet und die Anfrage in den Benutzer eingibt: Moskau Twerskaja 6. Dann verarbeitet der Server die Anfrage, empfängt Suchergebnisse von Yandex.Maps und sendet das resultierende Bild an den Client. Anschließend zeigt die TMap-Komponente im Client einen Teil einer bestimmten Karte an, der der Anforderung des Benutzers entspricht. Dadurch kann der Benutzer es skalieren, speichern usw.

Deshalb möchte ich Ihnen in diesem Artikel erzählen, wie ich den Client und den Server implementiert habe. Ich habe dies mit TClientSocket und TServerSocket gemacht. In diesem Artikel werden wir uns ausführlich mit den Methoden befassen, die ich in meinem Projekt verwendet habe.

Schauen wir uns zunächst an, wie Sie diese Komponenten in Ihrer IDE installieren können. Wenn Sie die IDE Delphi 7 verwenden, sind diese Komponenten standardmäßig vorhanden, aber leider nicht installiert, was jedoch kein Problem darstellt. Wir müssen nur Delphi öffnen und installieren.

Führen Sie dazu den Befehl Component-Install Packages... aus und klicken Sie im angezeigten Fenster auf die Schaltfläche Hinzufügen. Anschließend müssen Sie den Pfad zur Datei dclsockets70.bpl angeben, die sich standardmäßig im BIN-Ordner befindet. Danach müssen Sie auf die Schaltfläche OK klicken. Alle Ihre Komponenten sollten auf der Registerkarte „Internet“ angezeigt werden (TClientSocket und TServerSocket).

Im Projekt habe ich die gesamte Arbeit mit minimaler Serverentwicklung begonnen. Zuerst habe ich die TServerSocket-Komponente auf dem Formular installiert. Und indem ich auf die Schaltfläche „Server starten“ klicke, lege ich die Anfangseinstellungen fest, um ihn zu initialisieren:

Server. Port:=FormServerSetting. SpinEditPort. Wert ; //Geben Sie den Server-Port an Server. Aktiv: = Wahr; //aktiviere den Server. Offen ; wenn Server. Aktiv, dann beginnen //eine Meldung anzeigen, dass der Server betriebsbereit ist Ende ; …….. //einen Fehler anzeigen, wenn der Server nicht gestartet wurde

Um den Server auf meinem Rechner zu initialisieren, habe ich lediglich einen freien Port (der nicht von anderen Anwendungen belegt ist) angegeben und aktiviert.

Im Prinzip ist das alles, für meine Arbeit reichte es aus, dass der Server lief und ich die von ihnen gesendeten Client-Anfragen verarbeiten konnte.

Um eine Liste der Clients zu erhalten, die eine Verbindung zum Server herstellen und weiter mit ihnen arbeiten, habe ich die TCheckListBox-Komponente im Formular installiert und im OnclientConnect-Ereignis der TServerSocket-Komponente den folgenden Code geschrieben:

Prozedur TFormServer. ServerClientConnect (Sender: TObject; Socket: TCustomWinSocket) ; beginnen //Client-Verbindung überwachen RichEditLog. SelAttributes. Farbe:=clGrün; RichEditLog. SelAttributes. Stil: = [fsBold]; CheckListClient. Artikel. Add(Socket.RemoteHost); RichEditLog. Linien. Add ("[" + TimeToStr (Time ) + "] Client connected: " + Socket. RemoteHost ); //Füge den Client hinzu, der eine Verbindung zur Liste hergestellt hat RichEditLog. Perform (WM_VSCROLL, SB_BOTTOM, 0) ; Ende ;

Das heißt, ich füge der Liste die Namen der Clients hinzu, die eine Verbindung zum Server herstellen, um weitere Informationen über sie zu erhalten.

Sie können beispielsweise detaillierte Informationen zu einem Kunden erhalten:

Prozedur TFormInfoClient. FormShow(Sender: TObject); beginnen //Informationen über den Client anzeigen Bildunterschrift: = "Kundeninformation: "+FormServer. CheckListClient. Elemente[FormServer. CheckListClient. ItemIndex ] ; Lokaler Name. Bildunterschrift: = FormServer. Server. Steckdose. Verbindungen[FormServer. CheckListClient. ItemIndex] . LocalHost ; LocalHost. Bildunterschrift: = FormServer. Server. Steckdose. Verbindungen[FormServer. CheckListClient. ItemIndex] . Lokale Adresse ; LocalPort. Beschriftung: = IntToStr(FormServer. Server. Socket. Connections[ FormServer. CheckListClient. ItemIndex]. LocalPort); RemoteName. Bildunterschrift: = FormServer. Server. Steckdose. Verbindungen[FormServer. CheckListClient. ItemIndex] . Remote-Host ; Remote-Host. Bildunterschrift: = FormServer. Server. Steckdose. Verbindungen[FormServer. CheckListClient. ItemIndex] . RemoteAddress ; RemotePort. Beschriftung: = IntToStr(FormServer. Server. Socket. Connections[ FormServer. CheckListClient. ItemIndex]. RemotePort); Ende ;

Folgende Daten können erhoben werden:

  • Lokaler Name
  • Lokale Adresse
  • Lokaler Hafen
  • Name entfernt
  • Remote-Adresse
  • Remote-Port

Mithilfe dieses Codes, den ich in der Liste der TCheckListBox-Komponente ausgewählt habe, erhalte ich Informationen über den Client.

Wie Sie sehen, gibt es nichts Kompliziertes; um eine Nachricht an den Client zu senden, können Sie den folgenden Code verwenden:

In eckigen Klammern gebe ich an, an welchen Client wir die Nachricht senden (dies entspricht dem ausgewählten Client in der TCheckListBox-Komponente), ich gebe #message# in der Nachricht an – was bedeutet, dass es sich um eine reguläre Nachricht vom Server handelt, der gesendet werden soll einfach im Fenster angezeigt werden.

Um eine Nachricht vom Client an den Server zu empfangen, benötigen wir das OnClientRead-Ereignis der TServerSocket-Komponente und eine Textvariable, in der wir die vom Client gesendete Anfrage aufzeichnen.

Prozedur TFormServer. ServerClientRead(Sender: TObject; Socket: TCustomWinSocket) ; var-Abfrage: String ; beginnen //eine Anfrage vom Kunden für die Karte erhalten Versuchen Sie es mit der Abfrage: = Socket. Empfangstext ; if pos ("query" , Abfrage)<>0 dann beginnen //Anfrage von Yandex oder Google-Kartenkoordinaten, die der Anfrage des Kunden entsprechen Ende ; //Wenn es nur eine Nachricht vom Client ist, dann zeige sie an if pos ("#message#" , Abfrage)<>0 dann begin end ; ……

Anhand dieses Codes können Sie erkennen, dass der Client sowohl eine reguläre Nachricht an den Server als auch eine Anfrage zum Empfang einer Karte senden kann, z. B.: Moskau, Twerskaja, 6.

Dazu muss ich feststellen, wo sich die reguläre Nachricht befindet und wo genau die Anfrage zum Erhalt einer Karte steht, damit der Server diese anschließend verarbeiten kann. In diesem Fall füge ich den Nachrichten des Kunden ganz am Anfang die folgenden Bezeichner hinzu:

  • #Nachricht#
  • #Abfrage#

Wenn der Bezeichner #message# am Anfang der Nachricht des Clients vorhanden ist, erkennt der Server sie als reguläre Nachricht des Clients. Wenn die Kennung #query# am Anfang der Nachricht vorhanden ist, bedeutet dies, dass der Client eine Anfrage zum Erhalt einer Karte gesendet hat.

Außerdem kann ein Client jederzeit die Verbindung zum Server trennen; wir müssen dies auch verfolgen, um ihn aus der allgemeinen Liste der mit dem Server verbundenen Clients zu entfernen. Wählen Sie dazu die TServerSocket-Komponente aus und schreiben Sie den folgenden Code in das OnClientDisconnect-Ereignis:

Prozedur TFormServer. ServerClientDisconnect (Sender: TObject; Socket: TCustomWinSocket) ; var i: Ganzzahl ; Beginnen Sie mit dem Versuch //Client-Trennung überwachen RichEditLog. SelAttributes. Farbe:=clRed; RichEditLog. SelAttributes. Stil: = [fsBold]; für i : = 0 zum Server. Steckdose. ActiveConnections – 1 beginnen, wenn Server. Steckdose. Verbindungen[i]. Handle = Server. Steckdose. Verbindungen[i]. Handle und beginne dann mit RichEditLog. Linien. Add ("[" + TimeToStr (Time ) + "] Client getrennt: " + Socket. RemoteHost ); CheckListClient. Artikel. (i) streichen; RichEditLog. Perform (WM_VSCROLL, SB_BOTTOM, 0) ; Ende ; Ende ; endlich //-//-//-//-//-// end ; Ende ;

Wir gehen alle Clients durch, die wir in der Liste haben, und wenn wir keinen finden, entfernen wir ihn aus der TCheckListBox-Komponente. Das bedeutet, dass der Client in seiner Anwendung auf die Schaltfläche „Trennen“ geklickt hat.

Anfänger-Programmierer (und ich selbst, als ich anfing, Delphi zu lernen) stellen die Frage: Wie kann ich eine Datei über Sockets übertragen, wenn zusätzlich zu dieser Datei viele Informationen über den Socket übertragen werden!? Es scheint, dass das Problem nicht so kompliziert, aber dennoch nicht einfach ist ... Nach langer Suche im Internet habe ich immer noch keinen einzigen nützlichen Artikel zu diesem Thema gefunden. Deshalb habe ich beschlossen, diesen Mangel zu beheben, und in diesem Artikel werde ich versuchen, zur Lösung dieses Problems beizutragen ...

Schreiben wir ein Programm, das Dateien über Sockets (Client und Server) und zusätzlich andere Befehle, zum Beispiel eine Nachricht, übertragen kann! Der Client empfängt Dateien oder Befehle und der Server sendet sie. Wenn der Client alles in den Puffer schreibt, enthält dieser neben der Datei auch Befehle, und wir müssen sicherstellen, dass Dateien und Befehle auf keinen Fall zusammengeführt werden! Sie müssen auch berücksichtigen, dass, wenn die Datei groß ist, sie bei der Übertragung in mehrere Pakete aufgeteilt wird, d. h. die Datei wird nicht in einem Paket, sondern in mehreren Paketen gesendet und das OnClientRead-Ereignis wird aufgerufen mehrmals... Das ist das Hauptproblem der Übertragung!

Um Befehle von der Datei trennen zu können, senden wir dem Client zunächst etwa diese Zeile: „file#file.txt#16“, also: Befehl + Trennzeichen + Dateiname + Trennzeichen + Dateigröße.
Beim Empfang dieses Befehls wechselt der Client in den Dateiempfangsmodus und schreibt alles in den Puffer, bis die Dateigröße der Größe der empfangenen Daten entspricht. Auf diese Weise trennt der Client die Befehle von der Datei!

Beginnen wir also mit dem Schreiben von Code:
Beginnen wir mit dem Server (er sendet die Datei):

Platzieren Sie die folgenden Komponenten im Formular: TServerSocket, TButton, TEdit, TProgressBar und TStatiusBar. Platzieren Sie sie wie im Bild gezeigt.
Setzen Sie die TServerSocket-Komponente auf Port: 1001.
Setzen Sie die TStatusBar-Komponente und die SimplePanel-Variable auf true.
In der Zeile wird der Name der zu übertragenden Datei eingetragen, mit der Schaltfläche TButton wird die Datei übertragen.

Fügen wir zunächst einen Puffer für die Datei zu den globalen Variablen hinzu:

Var Form1: TForm1; MS: TMemoryStream; // Puffer für Datei

Stellen wir nun sicher, dass beim Erstellen eines Formulars ein Socket geöffnet wird:

Prozedur TForm1.FormCreate(Sender: TObject); begin ServerSocket1.Open; // Öffne das Socket-Ende;

Wenn die Anwendung beendet wird, müssen Sie daran denken, den Socket zu schließen:

Prozedur TForm1.FormDestroy(Sender: TObject); begin ServerSocket1.Close; // Das Socket-Ende schließen;

Wenn Sie auf die Schaltfläche klicken, senden wir die Datei:

Prozedur TForm1.Button1Click(Sender: TObject); // Datei übertragen var Size: integer; P: ^Byte; begin MS:= TMemoryStream.Create; // Einen Puffer für die Datei erstellen MS.LoadFromFile(Edit1.Text); // Datei in den Puffer laden // Informationen über die Datei senden (Befehl # Name # Größe) ServerSocket1.Socket.Connections.SendText("file#"+Edit1.Text+"#"+IntToStr(MS.Size)+" #") ; MS.Position:= 0; // Den Schlitten an den Anfang der Datei bewegen P:= MS.Memory; // Laden Sie die Dateigröße in die Variable „P“:= ServerSocket1.Socket.Connections.SendBuf(P^, MS.Size); // Datei senden // Fortschritt anzeigen ProgressBar1.Position:= Size*100 div MS.Size; StatusBar1.SimpleText:= „Gesendet „+IntToStr(Size)+“ von „+IntToStr(MS.Size)+“ Bytes“; Ende;

Geben Sie im OnClientRead-Ereignis der TServerSocket-Komponente den folgenden Code ein:

Prozedur TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); begin if Socket.ReceiveText = "end" then // Wenn der Client die Datei empfangen hat, dann... begin StatusBar1.SimpleText:= "Der Client hat die Datei empfangen"; MS.Free; // Töte den Puffer end; Ende;

Dies ist notwendig, damit der Server den Puffer erst beendet, nachdem der Client die Datei akzeptiert hat. Wenn Sie den Puffer unmittelbar nach der Übertragung der Datei löschen, hat der Client keine Zeit, die gesamte Datei zu empfangen! Sobald der Client die Datei akzeptiert, sendet er dem Server den Befehl „Ende“, was bedeutet, dass die Datei akzeptiert wurde und der Server den Puffer leert.

Lassen Sie uns nun dafür sorgen, dass unser Server einige Informationen über die Verbindung anzeigt:
Geben Sie im OnClientConnect-Ereignis der TServerSocket-Komponente den folgenden Code ein:

Prozedur TForm1.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket); begin StatusBar1.SimpleText:= "Verbindung hergestellt"; Ende;

Und geben Sie beim OnClientDisconnect-Ereignis Folgendes ein:

Prozedur TForm1.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); begin StatusBar1.SimpleText:= „Verbindung nicht hergestellt“; Ende;

Jetzt ist der Server bereit! Kommen wir nun zum Client (er akzeptiert die Datei), es wird noch mehr Aufregung damit geben:

Platzieren Sie die Komponenten im Forum: TClientSocket, zwei TLabels, TProgressBar und TStatusBar.
Setzen Sie die TClientSocket-Komponente auf Port: 1001 (wie der Server) und die Adressvariable: 127.0.0.1 (Ihre IP).
Vergessen Sie nicht, die TStatusBar-Komponente und die SimplePanel-Variable auf true zu setzen, damit unser Text sichtbar ist.
In einem TLabel wird der Dateiname angezeigt, in einem anderen die Dateigröße.
Am Ende sollten Sie etwas Ähnliches erhalten:

Wir deklarieren Variablen und eine Prozedur. Schreiben Sie die Variablen genau ein Privat, sonst geht nichts:

Prozedurschreiben (Text: string); // Verfahren zum Schreiben von Daten in den Puffer privat (Private Deklarationen) Name: string; // Dateiname Größe: integer; // Dateigröße Empfangen: boolean; // MS-Client-Modus: TMemoryStream; // Puffer für Datei

Beim Formularerstellungsereignis stellen wir eine Verbindung zum Server her und warten auf die Übertragung der Datei:

Prozedur TForm1.FormCreate(Sender: TObject); begin ClientSocket1.Open; // Den Socket öffnen Receive:= false; // Client-Modus – Empfang von Befehlen endet;

Wenn die Anwendung beendet wird, schließen Sie den Socket:

Prozedur TForm1.FormDestroy(Sender: TObject); begin ClientSocket1.Close; // Das Socket-Ende schließen;

Auf die gleiche Weise wie beim Server veranlassen wir den Client, Informationen über die Verbindung bereitzustellen:

Prozedur TForm1.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket); begin StatusBar1.SimpleText:= "Verbindung hergestellt"; Ende; procedure TForm1.ClientSocket1Disconnect(Sender: TObject; Socket: TCustomWinSocket); begin StatusBar1.SimpleText:= „Verbindung nicht hergestellt“; Ende;

Jetzt müssen wir den Code in den Schreibvorgang eingeben. Dieser Vorgang ist erforderlich, um empfangene Daten in eine Datei zu schreiben. Verfahrenscode:

Prozedur TForm1.Writing(Text: string); beginnen, wenn MS.Size< Size then // Если принято байт меньше размера файла, то... MS.Write(Text, Length(Text)); // Записываем в буфер // Выводим прогресс закачки файла ProgressBar1.Position:= MS.Size*100 div Size; StatusBar1.SimpleText:= "Принято "+IntToStr(MS.Size)+" из "+IntToStr(Size); if MS.Size = Size then // Если файл принят, то... begin Receive:= false; // Переводим клиента в нормальный режим MS.Position:= 0; // Переводим каретку в начало буфера MS.SaveToFile(Name); // Сохраняем файл ClientSocket1.Socket.SendText("end"); // Посылаем команду "end", то есть файл принят MS.Free; // Убиваем буфер StatusBar1.SimpleText:= "Файл принят"; end; end;

Geben Sie nun im OnClientRead-Ereignis der TClientSocket-Komponente den folgenden Code ein:

Prozedur TForm1.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket); var Rtext: string; // Empfangener Text begin Rtext:= Socket.ReceiveText; if Receive then // Wenn sich der Client im Dateiempfangsmodus befindet, dann... Writing(RText) // Daten in den Puffer schreiben else // Wenn sich der Client nicht im Dateiempfangsmodus befindet, dann... begin if Copy( Rtext, 0, Pos ("#", Rtext) -1) = "file" then // Wenn dies eine Datei ist, dann... begin MS:= TMemoryStream.Create; // Puffer für die Datei erstellen Delete(Rtext, 1, Pos("#", Rtext)); // Dateinamen ermitteln Name:= Copy(Rtext, 0, Pos("#", Rtext) -1); // Dateinamen ermitteln Delete(Rtext, 1, Pos("#", Rtext)); // Dateigröße ermitteln Size:= StrToInt(Copy(Rtext, 0, Pos("#", Rtext) -1)); // Bestimmen Sie die Dateigröße. Delete(Rtext, 1, Pos("#", Rtext)); // Letztes Trennzeichen entfernen Label1.Caption:= "Dateigröße: "+IntToStr(Size)+" Bytes"; // Dateigröße anzeigen Label2.Caption:= "Dateiname: "+Name; // Den Dateinamen ausgeben Receive:= true; // Den Server in den Dateiempfangsmodus schalten Writing(RText); // Daten an das Pufferende schreiben; Ende; Ende;

Wenn also die Datei groß ist und das OnClientRead-Ereignis nicht einmal, sondern mehrmals aufgerufen wird, schreibt der Client, wenn er sich im Dateiempfangsmodus befindet, Daten in den Puffer. Wenn nicht, ermittelt der Client die Daten empfangenen Befehl, und wenn es sich um eine Datei handelt, wechselt er in den Dateiempfangsmodus. Wenn du etwas nicht verstehst, dann lies den Programmcode, nicht umsonst habe ich dort alles auskommentiert :-)

OK, jetzt ist alles vorbei...
Client und Server sind bereit! Starten Sie zuerst den Server und dann den Client und versuchen Sie, mehrere Megabyte große Dateien zu übertragen :-) Ich habe problemlos Dateien mit einer Größe von 10-12 MB über das Netzwerk gesendet.

Viel Spaß beim Programmieren!

Einführung

Dieser Artikel widmet sich der Erstellung von Client/Server-Architekturanwendungen in Borland Delphi basierend auf Sockets („Sockets“). Und ich habe diesen Artikel aus einem bestimmten Grund geschrieben, aber weil diese Frage in letzter Zeit für viele Menschen interessant geworden ist. Wir gehen zunächst nur auf die Erstellung des Client-Teils der Socket-Anwendung ein.
Mit Steckdosen bin ich, wenn ich mich nicht irre, zum ersten Mal vor einem oder anderthalb Jahren bekannt geworden. Dann bestand die Aufgabe darin, ein Anwendungsprotokoll zu entwickeln, das eine Anfrage an einen Server-Rechner (unter Unix/Linux-Betriebssystem) übermittelt und über einen Socket-Kanal eine Antwort empfängt. Es ist zu beachten, dass im Gegensatz zu allen anderen Protokollen (FTP, POP, SMTP, HTTP usw.) Sockets die Grundlage für diese Protokolle bilden. So können Sie mithilfe von Sockets FTP, POP und jedes andere Protokoll selbst erstellen (simulieren), und zwar nicht unbedingt ein bereits erstelltes, sondern sogar Ihr eigenes!

Beginnen wir also mit der Theorie. Wenn Sie ein überzeugter Praktiker sind (und mit Ihren Augen keine Algorithmen erkennen können), dann sollten Sie diesen Abschnitt überspringen.

Algorithmus zum Arbeiten mit Socket-Protokollen

Was ermöglichen uns Steckdosen? ... Ja, alles! Und das ist einer der Hauptvorteile dieser Methode des Datenaustauschs im Netzwerk. Tatsache ist, dass Sie bei der Arbeit mit einem Socket einfach eine Zeichenfolge an einen anderen Computer senden. Mit dieser Methode können Sie also sowohl einfache Nachrichten als auch ganze Dateien versenden! Außerdem müssen Sie die Korrektheit der Übertragung nicht kontrollieren (wie es bei der Arbeit mit COM-Ports der Fall war)!
Unten finden Sie ein Beispieldiagramm für die Arbeit mit Sockets in Delphi-Anwendungen:

Definieren von Host- und Porteigenschaften >>> Starten eines Sockets (ClientSocket1.Open) >>> Autorisierung >>> Senden/Empfangen von Daten >>> Schließen eines Sockets

Schauen wir uns das Diagramm genauer an:
Definieren der Host- und Port-Eigenschaften – um erfolgreich eine Verbindung herzustellen, müssen Sie den Host- und Port-Eigenschaften der TClientSocket-Komponente die erforderlichen Werte zuweisen. Host ist der Hostname (zum Beispiel: nitro.borland.com) oder die IP-Adresse (zum Beispiel: 192.168.0.88) des Computers, zu dem Sie eine Verbindung herstellen möchten. Port – Portnummer (von 1 bis 65535) zum Herstellen einer Verbindung. Typischerweise werden Portnummern ab 1001 vergeben – weil Nummern unter 1000 können von Systemdiensten belegt sein (z. B. POP - 110). Weitere Details zum praktischen Teil finden Sie weiter unten;
Öffnen eines Sockets – Nachdem Sie den Host- und Port-Eigenschaften die entsprechenden Werte zugewiesen haben, können Sie direkt mit dem Öffnen des Sockets fortfahren (ein Socket wird hier als eine Warteschlange betrachtet, die von einem Computer an einen anderen übertragene Zeichen enthält). Dazu können Sie die Open-Methode der TClientSocket-Komponente aufrufen oder die Active-Eigenschaft auf True setzen. Hier ist es sinnvoll, einen Ausnahmehandler zu installieren, falls die Verbindung fehlschlägt. Mehr dazu erfahren Sie weiter unten im praktischen Teil;
Autorisierung – Dieses Element kann übersprungen werden, wenn der Server keine Eingabe von Logins und/oder Passwörtern erfordert. In dieser Phase senden Sie dem Server Ihren Login (Benutzernamen) und Ihr Passwort. Der Autorisierungsmechanismus hängt jedoch vom jeweiligen Server ab;
Das Senden/Empfangen von Daten ist eigentlich der Zweck, für den die Socket-Verbindung geöffnet wurde. Das Kommunikationsprotokoll hängt auch vom Server ab;
Einen Socket schließen – nachdem alle Vorgänge abgeschlossen sind, müssen Sie den Socket mit der Close-Methode der TClientSocket-Komponente schließen (oder die Active-Eigenschaft auf False setzen).

Beschreibung der Eigenschaften und Methoden der TClientSocket-Komponente

Hier machen wir uns mit den wichtigsten Eigenschaften, Methoden und Ereignissen der TClientSocket-Komponente vertraut.

Eigenschaften
Aktiv – zeigt an, ob der Socket geöffnet ist oder nicht. Typ: Boolesch. Dementsprechend ist True offen und False geschlossen. Diese Eigenschaft ist beschreibbar;
Host – eine Zeichenfolge (Typ: Zeichenfolge), die den Hostnamen des Computers angibt, zu dem eine Verbindung hergestellt werden soll;
Adresse – eine Zeichenfolge (Typ: Zeichenfolge), die die IP-Adresse des Computers angibt, mit dem Sie eine Verbindung herstellen möchten. Im Gegensatz zu Host kann dieser nur IP enthalten. Der Unterschied besteht darin, dass, wenn Sie in Host einen symbolischen Computernamen angeben, die diesem Namen entsprechende IP-Adresse vom DNS angefordert wird;
Port – Portnummer (Typ: Ganzzahl (Wort)), mit der eine Verbindung hergestellt werden soll. Gültige Werte liegen zwischen 1 und 65535;
Dienst – eine Zeichenfolge (Typ: Zeichenfolge), die den Dienst (ftp, http, pop usw.) definiert, zu dem die Verbindung hergestellt werden soll. Dabei handelt es sich um eine Art Verzeichnis von Portnummern, die verschiedenen Standardprotokollen entsprechen;
ClientType – Verbindungstyp. ctNonBlocking – asynchrone Datenübertragung, d.h. Mit OnRead und OnWrite können Sie Daten gleichzeitig über einen Socket senden und empfangen. ctBlocking – synchrone Datenübertragung. Die Ereignisse OnRead und OnWrite funktionieren nicht. Diese Art der Verbindung ist nützlich, um den Datenaustausch mithilfe von Streams zu organisieren (d. h. mit einem Socket als Datei zu arbeiten);

Methoden
Open – Öffnen eines Sockets (ähnlich dem Zuweisen des Werts True zur Active-Eigenschaft);
Close – Schließen des Sockets (ähnlich der Zuweisung des Werts False zur Active-Eigenschaft);

Hier sind alle Methoden der TClientSocket-Komponente ausgeschöpft. Und Sie fragen: „Aber wie arbeitet man mit einem Socket? Wie sendet man dann Daten?“ Darüber erfahren Sie etwas weiter.

Praxis und Beispiele

Der einfachste (und nützlichste) Weg, eine Programmiermethode zu erlernen, besteht darin, sie zu üben. Im Folgenden finden Sie daher Beispiele mit einigen Kommentaren:

Beispiel 1. Das einfachste Socket-Programm

(Sie müssen eine TButton-Schaltfläche und zwei TEdits in das Formular einfügen. Wenn Sie auf die Schaltfläche klicken, wird der OnClick-Ereignishandler – Button1Click – aufgerufen. Zuvor müssen Sie den Hostnamen in das erste der TEdits eingeben und den Port des Remote-Computers im zweiten. VERGESSEN SIE NICHT, DIE KOMPONENTE IN DER FORM TClientSocket ZU PLATZIEREN !}


beginnen
(Weisen Sie den Host- und Port-Eigenschaften die erforderlichen Werte zu)
ClientSocket1.Host:= Edit1.Text;
ClientSocket1.Port:= StrToInt(Edit2.Text);
(Wir versuchen den Socket zu öffnen und eine Verbindung herzustellen)
ClientSocket1.Open;
Ende;


beginnen
(Sobald die Verbindung zustande gekommen ist, schließen Sie den Socket und unterbrechen Sie die Verbindung)
ClientSocket1.Close;
Ende;

Wenn Sie denken, dass dieses Beispielprogramm völlig nutzlos ist und keinen Nutzen bringen kann, dann irren Sie sich zutiefst. Der angegebene Code ist das einfachste Beispiel eines Port-Scanners (PortScanner). Der Kern eines solchen Dienstprogramms besteht darin, zu überprüfen, ob der angegebene Port aktiviert ist und ob er zum Empfangen/Übertragen von Daten bereit ist. Auf diesem Prinzip basiert PortScanner aus dem Programm NetTools Pro.

Beispiel 2. Senden/Empfangen von Textnachrichten über Sockets

(Sie müssen zwei TButtons und drei TEdits im Formular platzieren. Wenn Sie auf die erste Schaltfläche klicken, wird der OnClick-Ereignishandler – Button1Click – aufgerufen. Zuvor müssen Sie den Hostnamen in das erste der TEdits eingeben und den Port des Remote-Computers im zweiten. Nachdem die Verbindung hergestellt ist, können Sie Textnachrichten senden, indem Sie im dritten TEdit Text eingeben und den zweiten TButton drücken. Um die Verbindung zu trennen, müssen Sie den ersten TButton erneut drücken. Sie müssen auch hinzufügen eine TListBox, in der wir empfangene und gesendete Nachrichten platzieren. VERGESSEN SIE NICHT, DIE TClientSocket-KOMPONENTE IN DAS FORMULAR ZU PLATZIEREN !}

procedure Button1Click(Sender: TObject);
beginnen
(Falls die Verbindung bereits besteht, unterbrechen Sie diese.)
Wenn ClientSocket1.Active, dann beginnen
ClientSocket1.Close;
Ausfahrt; (...und den Handler verlassen)
Ende;
(Weisen Sie den Host- und Port-Eigenschaften die erforderlichen Werte zu)
ClientSocket1.Host:= Edit1.Text;
ClientSocket1.Port:= StrToInt(Edit2.Text);
(Wir versuchen den Socket zu öffnen und eine Verbindung herzustellen)
ClientSocket1.Open;
Ende;


beginnen
(Sobald die Verbindung zustande kommt, senden wir eine Begrüßung)
Socket.SendText(′Hallo!′);
ListBox1.Items.Add(′< Hello!′);
Ende;

procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
beginnen
(Wenn eine Nachricht angekommen ist, fügen Sie sie der ListBox hinzu)
ListBox1.Items.Add(′> ′+Socket.ReceiveText);
Ende;

procedure Button2Click(Sender: TObject);
beginnen
(Taste gedrückt – Text vom dritten TEdit senden)
ClientSocket1.Socket.SendText(Edit3.Text);
ListBox1.Items.Add(′< ′+Edit3.Text);
Ende;

HINWEIS: In manchen Fällen (je nach Server) ist es notwendig, nach jeder Nachricht einen Zeilenvorschub zu senden:
ClientSocket1.Socket.SendText(Edit3.Text+#10);

Arbeiten mit einem Socket-Stream

„Wie sonst kann man mit einer Steckdose arbeiten?“, fragen Sie. Natürlich ist die obige Methode nicht die beste Lösung. Es gibt viele Methoden, die Arbeit mit Steckdosen zu organisieren. Ich möchte nur noch eine weitere Sache nennen – die Arbeit durch einen Stream. Sicherlich haben viele von Ihnen bereits Erfahrung in der Arbeit, wenn nicht mit Streams, dann mit Sicherheit mit Dateien. Für diejenigen, die es nicht wissen: Ein Stream ist ein Kanal zum Austausch von Daten. Die Arbeit damit ähnelt der Arbeit mit einer normalen Datei. Das folgende Beispiel zeigt, wie man einen Thread für die Arbeit an einem Socket organisiert:

Beispiel 3. Thread zum Arbeiten mit einem Socket

procedure ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
var c: Char;
MySocket: TWinSocketStream;
beginnen
(Sobald die Verbindung zustande gekommen ist, erstellen wir einen Thread und verknüpfen ihn mit dem Socket (60000 - Timeout in ms))
MySocket:= TWinSocketStream.Create(Socket,60000);
(Der WaitForData-Operator wartet für die angegebene Zeit in ms (in diesem Beispiel 100) auf Daten aus dem Stream und gibt True zurück, wenn mindestens ein Byte Daten empfangen wurde, und False, wenn keine Daten aus dem Stream vorhanden sind.)
während MySocket.WaitForData(100) dies nicht tut
Application.ProcessMessages;
(Application.ProcessMessages ermöglicht es Windows, die notwendigen Elemente des Fensters neu zu zeichnen und gibt anderen Programmen Zeit. Wenn diese Anweisung nicht vorhanden wäre und die Daten längere Zeit nicht eintreffen würden, würde das System leicht einfrieren.)
MySocket.Read(c,1);
(Der Read-Operator liest eine angegebene Anzahl von Bytes aus einem Stream (in diesem Beispiel 1) in eine angegebene Variable eines bestimmten Typs (in diesem Beispiel in eine Char-Variable c). Beachten Sie, dass Read im Gegensatz zu ReadBuffer keine Auferlegung durchführt strenge Einschränkungen hinsichtlich der Menge der empfangenen Informationen. Das heißt, Read liest höchstens n Bytes aus dem Stream (wobei n die angegebene Zahl ist. Diese Funktion gibt die Anzahl der empfangenen Datenbytes zurück.)
MySocket.Write(c,1);
(Die Write-Anweisung ähnelt der Read-Anweisung, außer dass Write Daten in einen Stream schreibt.)
MySocket.Free;
(Vergessen Sie nicht, den für den Thread zugewiesenen Speicher freizugeben.)
Ende;

HINWEIS: Um einen Stream zu verwenden, stellen Sie sicher, dass die ClientType-Eigenschaft auf ctBlocking festgelegt ist.

Komplexe Daten senden/empfangen

Manchmal ist es notwendig, nicht nur einfache Textnachrichten über das Netzwerk zu senden, sondern auch komplexe Strukturen (der Datensatztyp in Pascal) oder sogar Dateien. Und dann müssen Sie spezielle Operatoren verwenden. Einige davon sind unten aufgeführt:

Methoden TClientSocket.Socket (TCustomWinSocket, TClientWinSocket):
SendBuf(var Buf; Count: Integer) – Senden eines Puffers über den Socket. Der Puffer kann einen beliebigen Typ haben, sei es eine Struktur (Datensatz) oder eine einfache Ganzzahl. Der Puffer wird durch den Buf-Parameter angegeben, im zweiten Parameter müssen Sie die Größe der übertragenen Daten in Bytes (Count) angeben;
SendText(const S: string) – Senden Sie eine Textzeichenfolge über einen Socket. Diese Methode wurde in Beispiel 2 besprochen (siehe oben);
SendStream(AStream: TStream) – Sendet den Inhalt des angegebenen Streams über einen Socket. Der weitergeleitete Stream muss geöffnet sein. Der Stream kann von beliebigem Typ sein – Datei, aus dem RAM usw. Eine Beschreibung der direkten Arbeit mit Threads würde den Rahmen dieses Artikels sprengen;
Alle aufgeführten Methoden entsprechen dem Empfangen... Ihre Beschreibung finden Sie in der Delphi-Hilfedatei (VCL-Hilfe).

Abschließend möchte ich noch ein einfaches Beispiel geben, wie Sie die Autorisierung (Anmeldung am Server) umsetzen können. In diesem Beispiel wird das Passwort im Klartext gesendet. Wenn Sie also einen wirklich sicheren Anmeldemechanismus wünschen, müssen Sie einige Änderungen am Quellcode dieses Beispiels vornehmen. Das Beispiel ist als Arbeit mit einem Socket-Stream implementiert.

(In diesem Beispiel müssen Sie dem Formular zwei weitere TEdits hinzufügen – Edit3 und Edit4 für die Eingabe Ihres Benutzernamens und Passworts.)

procedure ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
var c: Char;
MySocket: TWinSocketStream;
Login, Passwort: string;
beginnen
MySocket:= TWinSocketStream.Create(Socket,60000);
(Wir fügen dem Benutzernamen und dem Passwort ein Zeilenumbruchzeichen hinzu, damit der Server den Benutzernamen und das Passwort trennen kann.)
login:= Edit3.Text+#10;
Passwort:= Edit4.Text+#10;
MySocket.Write(login,Length(Edit3.Text)+1);
MySocket.Write(password,Length(Edit4.Text)+1);
während MySocket.WaitForData(100) dies nicht tut
Application.ProcessMessages;
MySocket.Read(c,1);
(Hier sendet uns der Server ein Byte, dessen Wert 1 der Bestätigung einer erfolgreichen Autorisierung entspricht und 0 einem Fehler entspricht (dies ist nur ein Beispiel). Als nächstes führen wir die erforderlichen Aktionen aus (Empfangen/Senden von Daten) und schließen die Strom.)
MySocket.Free;
Ende