Umíme to s Delphi: 126. díl – klientská aplikace přes sockety

Pokud nevěříte, že je možné zprovoznit síťovou TCP komunikaci pouhými několika řádky programového kódu, nahlédněte do dnešního článku Vytvoříme společně TCP klienta, který se bude umět připojit k TCP serveru a posílat mu textové zprávy.

V minulém dílu seriálu jsme si krok za krokem vysvětlili a ukázali, jakým způsobem vytvořit v Delphi jednoduchý TCP/IP server. Serverová aplikace nám sice fungovala, nicméně nemohla předvést, co se v ní skrývá, protože dosud neexistují žádní klienti, kteří by se k ní připojili. Tento drobný nedostatek dnes napravíme, neboť náplň článku bude spočívat v naprogramování jednoduchého klienta, který dokáže komunikovat s naším serverem z předchozího dílu.

K tomu, abyste si mohli dnešní článek jaksepatří vychutnat, je tedy nezbytné, abyste měli naprogramovanou aplikaci z minulého dílu. Server byl velice jednoduchý a jsem si jist, že všichni čtenáři Živě jeho naprogramování zvládli.

Na samotný úvod zopakuji ještě jedno důležité upozornění: postup popsaný v dnešním článku si opět nebudou moci prakticky zkusit majitelé Delphi 7. Základní komponenty použité v předchozí i dnešní aplikaci (ServerSocket a ClientSocket ze záložky Internet), byly totiž v Delphi 7 odebrány a nahrazeny novými, sice výkonnějšími, ale zato komplikovanějšími. Ale i k těm se dostaneme, majitelé Delphi 7 se proto nemusejí obávat, že jim zůstanou taje socketů skryté.

Ještě než se dáme do práce, zopakujeme si, co vlastně server z minulého dílu umí. Tato informace je při vytváření klientů poměrně zásadní :)

Server je velmi jednoduchý. Po spuštění pouze čeká na připojení klientů, přičemž je poslouchá na svém portu číslo 5050. Z toho pro klienty plyne jeden zásadní důsledek: aby klient mohl přistoupit k tomuto serveru, musí kromě adresy serveru uvést také číslo portu 5050.

Po připojení klienta vypíše server informační hlášení říkající, že došlo k připojení. Podobně se zachová po odpojení kteréhokoliv klienta. Do seznamu ListBox vypisuje server textová data, která jí zasílají připojení klienti. Toť vše, nic víc a nic míň náš chytrý server neumí.

Vzhůru do klientů

Úvodní proslov máme úspěšně za sebou a můžeme se směle pustit do programování klientských aplikací. Co bude náš klient umět?

Nutno poznamenat, že nic moc. Aplikace bude sloužit jako jednoduchý TCP/IP klient, takže bude umožňovat zadání IP adresy serveru a připojení k tomuto serveru. Další podporovanou operací bude zaslání dat (textové zprávy) připojenému serveru a odpojení od serveru. Tím jsou schopnosti našeho klienta vyčerpány.

Ač se to zdá nemožné, vytvoření aplikace bude ještě nepatrně jednodušší než vytvoření serveru:

1. Vytvořte v Delphi novou aplikaci, a na formulář umístěte následující komponenty: 2x editační pole (Edit), 2x nápis (Label), 3x tlačítko (Button) a komponentu ClientSocket ze záložky Internet. Znovu připomínám, že tuto komponentu budou marně hledat majitelé Delphi 7. Možný vzhled aplikace je na následujícím obrázku:

Klepněte pro větší obrázek

2. Nejprve ošetříme událost OnCreate hlavního formuláře. V její obsluze nastavíme potřebné titulky komponent, ale především nastavíme typ klienta na neblokující a dále nastavíme číslo portu, k němuž se hodláme připojovat, na 5050 (připomeňme, že server – viz minulý článek – poslouchá na tomto čísle portu). O tom, co znamená neblokující klient, si budeme vyprávět v některém z příštích článků, prozatím jen velmi stručně: blokující klient by se choval tak, že po kterékoliv operaci (odeslání dat na server) by byl zablokován až do okamžiku, kdy by byla operace dokončena, zatímco neblokující klient běží ihned vesele dál.

procedure TForm1.FormCreate(Sender: TObject);
begin
  Caption := `Klientská aplikace pøes sockety - odpojeno`;
  Button1.Caption := `&Pøipoj`;
  Button2.Caption := `&Odpoj`;
Button3.Caption := `&Pošli data`;
Label1.Caption := `Zadejte adresu serveru`;
Label2.Caption := `Zadejte data k odeslani`;

  Button2.Enabled := False;
  Button3.Enabled := False;
  Edit1.Text := `127.0.0.1`;
  Edit2.Text := ``;

  // nastaveni klienta
  ClientSocket1.ClientType := ctNonBlocking;  // neblokujici spojeni
  ClientSocket1.Port := 5050;                // pripojujeme se k portu 5050
end;

3. Následně ošetříme událost OnClick tlačítka Button1. Tlačítko Button1 bude sloužit k připojení k serveru.

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Edit1.Text <> `` then
    ClientSocket1.Address := Edit1.Text
  else
    ClientSocket1.Address := `127.0.0.1`;      // nezadano->lokalni pocitac

  ClientSocket1.Open;                          // navazeme spojeni
end;

Je patrné, že IP adresa vzdáleného serveru se zadává do vlastnosti Address komponenty ClientSocket. Pro navázáni spojeni (pro připojení k serveru) použijeme metodu ClientSocket.Open. Připomeňme, že pro správně fungující komunikaci je nutné zadat ještě číslo portu, to jsme provedli v rámci obsluhy události OnCreate.

4. Dále ošetříme událost OnClick tlačítka Button2. Tlačítko Button2 slouží k odpojení klienta od serveru (ke zrušení spojení). Odpojení od serveru není vůbec obtížné:

// Button2 - odpojeni od serveru
procedure TForm1.Button2Click(Sender: TObject);
begin
  ClientSocket1.Close;                          // zrusime spojeni
end;

5. Posledním nutným krokem je ošetření události OnClick tlačítka Button3. Toto tlačítko bude sloužit k odeslání dat na server. Také odeslání dat je nesmírně jednoduché: postačí nám zavolat metodu ClientSocket.Socket.SendText, do jejíhož parametru předáme požadovanou zprávu pro server:

// Button3 - zaslani dat
procedure TForm1.Button3Click(Sender: TObject);
begin
  ClientSocket1.Socket.SendText(Edit2.Text);    // posleme text
end;

6. Nyní ošetříme dvě události komponenty ClientSocket, a to OnConnect a OnDisconnect. První z nich vznikne bezprostředně po úspěšném připojení k serveru (a její obsluhu využijeme k nastavení titulku okna a ke správnému nastavení dostupnosti tlačítek), druhá pak naopak po ukončení spojení:

procedure TForm1.ClientSocket1Connect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Caption := `Klientská aplikace pøes sockety - pripojeno`;
  Button1.Enabled := False;
  Button2.Enabled := True;
  Button3.Enabled := True;
end;

procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Caption := `Klientská aplikace pøes sockety - odpojeno`;
  Button1.Enabled := True;
  Button2.Enabled := False;
  Button3.Enabled := False;
end;

6. Poslední maličkost spočívá v ošetření události OnClose formuláře. Pro případ, že by nezbedný uživatel před ukončením práce neodpojil klienta od serveru, provedeme odpojení za něho:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  ClientSocket1.Close;
end;

Tím jsme prakticky hotovi. Ještě než se slavnostně pokusíme poslat sami sobě náš první TCP/IP pozdrav, dodejme k aplikaci několik maličkostí:

  • Po klepnutí na Button1 dojde k připojení k serveru (voláním ClientSocket1.Open, stejně tak by bylo ale možné nastavit ClientSocket1.Active := True). Server je tedy identifikován IP adresou (buď adresa v Edit1 nebo 127.0.0.1) a číslem portu (5050).
  • Odpojení od serveru se provede zavoláním Close (případně nastavením Active na False).

Zkoušíme komunikaci

Nyní můžeme vyzkoušet, zda všechno funguje. Nejprve přeložíme a spustíme výsledek dnešní práce – klienta (viz následující obrázek):

Klepněte pro větší obrázek

Klient běží, ale je prozatím odpojen. Když klepneme na tlačítko Připojit, dojde k ohlášení výjimky ESocketError s hláškou Asynchronous Socket Error, viz obrázek:

Klepněte pro větší obrázek

Tato výjimka je standardně generována v případě, že dojde k chybě v průběhu navazování spojení, například když se aplikace pokouší změnit parametry již otevřeného socketu, nebo když se objeví chyba při zápisu/čtení do/ze socketu, nebo když socket nemůže být korektně ukončen. A nebo také nemůže-li být socket otevřen, což je náš případ, neboť server dosud neběží (takže se k němu poměrně těžko připojíme).

Rád bych upozornil ještě na jednu věc. Je třeba si uvědomit, že i když to tak nemusí vypadat, naprogramovali jsme ryze síťovou aplikaci. Takže: pokud máte k dispozici síťové prostředí, můžete si později vyzkoušet plnohodnotnou síťovou komunikace: server umístíte na jeden počítač v síti a klienta (klienty) na jiný (na jiné). Klienti budou muset znát IP adresu serveru, aby se k němu mohly připojit.

Pokud však nemáte síť, můžete spustit server i klienty na jednom a tomtéž počítači. Při komunikaci pak zadávejte adresu 127.0.0.1, což je adresa lokálního počítače. Klienti pak budou hledat server přímo na lokálním počítači a budou komunikovat lokálně.

Zůstane však zachován princip síťové komunikace. Vše bude vypadat jako síťová komunikace, protože adresa 127.0.0.1 má zcela analogické použití jako kterákoliv jiná IP adresa (např. 147.228.59.11). Jediný rozdíl je, že cílové umístění této adresy leží vždy tam, kde ji použijete.

Co z toho plyne? Komunikujete-li přes adresu 127.0.0.1, komunikujete sice sami se sebou, ale ze systémového hlediska provozujete korektní síťovou komunikaci. A proto pokud máte např. instalován nějaký firewall nebo jiný program monitorující a kontrolující síťový provoz, zareaguje tento program na pokus o připojení k serveru informačním hlášením, viz následující obrázek (jsem si vědom smutného faktu, že na obrázku je starší verze firewallu, ale snad mi to odpustíte :))

Klepněte pro větší obrázek

Firewall mě informuje, že aplikace PROJECT1.EXE (tj. klient) se hodlá síťově připojovat na adresu 127.0.0.1 (vůbec přitom nevadí, že jsem to zase já – jde o síťovou komunikaci jako každá jiná) na port 5050 prostřednictvím protokolu TCP. Firewall se mě táže, zda má pokus o toto připojení povolit nebo zakázat.

Komunikujeme se serverem

Pojďme se však konečně podívat na fungující komunikaci. Abychom mohli komunikovat, musíme spustit TCP server vytvořený v minulém díle seriálu. Spustíme tedy příslušný soubor (ať již na lokálním počítači nebo kdekoliv v síti).

Následně spustíme jednoho nebo více klientů vytvořených dnes. Opět nezáleží na tom, zda je pustíme na stejném počítači jako server a nebo zda je rozmístíme po síti. Na principu se vůbec nic nemění. Pro jednoduchost (a pro názornost obrázků) použiji lokální počítač, na němž spustím server a dva klienty, viz obrázek:

Klepněte pro větší obrázek

Nyní mohu klienty připojit a poslat jim nějaká data; na serveru se budou zobrazovat příslušná hlášení. Navázali jsem fungující TCP/IP spojení, viz obrázek:

Klepněte pro větší obrázek

Mimochodem, všimněte si, co se stane, když v tuto chvíli vypnete server. Spojení je automaticky ukončeno a klienti dostanou událost OnDisconnect. Nestane se tedy, že by klient komunikoval v dommění, že server poslouchá a server už by byl dávno vypnutý. Vzhledem k tomu, že jsme ošetřili událost klientů OnDisconnect, budou po vypnutí serveru i psrávně nastaveny titulky klientů a jejich tlačítka.

Chcete-li se přesvědčit, že naše aplikace funguje i ve skutečném síťovém prostředí, nejen na lokálním počítači, máte k dispozici následující obrázek:

Klepněte pro větší obrázek

Zdrojový kód

Pro úplnost si opět uvedeme kompletní zdrojový kód klienta. Můžete znovu posoudit, jak krátký kód stačí k tomu, abychom pomocí Delphi zprovoznili fungující síťovou aplikaci.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ScktComp;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    ClientSocket1: TClientSocket;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure ClientSocket1Connect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocket1Disconnect(Sender: TObject;
      Socket: TCustomWinSocket);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Caption := `Klientská aplikace pøes sockety - odpojeno`;
  Button1.Caption := `&Pøipoj`;
  Button2.Caption := `&Odpoj`;
  Button3.Caption := `&Pošli data`;
  Label1.Caption := `Zadejte adresu serveru`;
  Label2.Caption := `Zadejte data k odeslani`;

  Button2.Enabled := False;
  Button3.Enabled := False;
  Edit1.Text := `127.0.0.1`;
  Edit2.Text := ``;

  // nastaveni klienta
  ClientSocket1.ClientType := ctNonBlocking;  // neblokujici spojeni
  ClientSocket1.Port := 5050;                // pripojujeme se k portu 5050
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Edit1.Text <> `` then
    ClientSocket1.Address := Edit1.Text
  else
    ClientSocket1.Address := `127.0.0.1`;      // nezadano->lokalni pocitac

  ClientSocket1.Open;                          // navazeme spojeni
end;

// Button2 - odpojeni od serveru
procedure TForm1.Button2Click(Sender: TObject);
begin
  ClientSocket1.Close;                          // zrusime spojeni
end;

// Button3 - zaslani dat
procedure TForm1.Button3Click(Sender: TObject);
begin
  ClientSocket1.Socket.SendText(Edit2.Text);    // posleme text
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  ClientSocket1.Close;
end;

procedure TForm1.ClientSocket1Connect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Caption := `Klientská aplikace pøes sockety - pripojeno`;
  Button1.Enabled := False;
  Button2.Enabled := True;
  Button3.Enabled := True;
end;

procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Caption := `Klientská aplikace pøes sockety - odpojeno`;
  Button1.Enabled := True;
  Button2.Enabled := False;
  Button3.Enabled := False;
end;

end.

Na závěr

Dnešní díl seriálu dokončil vytváření ukázkových aplikací demonstrujících síťovou komunikaci přes sockety. Vytvořili jsme jednoduchého TCP klienta, který je schopen připojit se ke vzdálenému serveru na port 5050 a zaslat mu textovou zprávu.

Důležité je, že vytvoření fungujícího TCP klienta a serveru je nesmírně snadnou záležitostí a vystačíme si při něm s několika řádky zdrojového kódu. Výsledné aplikace přitom dokáží komunikovat po síti. V této jednoduchosti je úžasná síla Delphi. Mohlo by být programování síťových aplikací vůbec ještě jednodušší?

Diskuze (10) Další článek: Morseovka bude po 60 letech aktualizována

Témata článku: Software, Programování, DEL, Síťová komunikace, Server, Minulý článek, Klient, Socket, Úvodní proslov, SoC, Klientská aplikace, Síťová IP, Serverová aplikace, Síťová data, Díl, Následující aplikace


Určitě si přečtěte

Biblická potopa Česka: Jak bychom dopadli, kdyby nás zatopil oceán

Biblická potopa Česka: Jak bychom dopadli, kdyby nás zatopil oceán

** Představte si biblickou potopu ** Nejprve zaniknou Děčín a Břeclav, pak i Brno a Praha ** Hlavním městem se stane Jihlava a zbytky Čechů přežijí na Kvildě

Jakub Čížek | 92

Už desítky let se pokoušíme odposlouchávat mozek. Rusům se podařil kousek, ze kterého vám spadne brada

Už desítky let se pokoušíme odposlouchávat mozek. Rusům se podařil kousek, ze kterého vám spadne brada

** K odposlechu mozků používáme EEG ** To má ale žalostné informační rozlišení ** Rusům pomohla počítačová neuronová síť

Jakub Čížek | 28

Windows 10 podle našich čtenářů: Poslali jste nám skoro 300 nápadů, jak je vylepšit

Windows 10 podle našich čtenářů: Poslali jste nám skoro 300 nápadů, jak je vylepšit

** Microsoft aktualizuje Windows 10 dvakrát ročně ** Jenže praktických novinek už není tolik jako dříve ** Poslali jste nám skoro 300 tipů, co by se měly Desítky ještě naučit

Jakub Čížek | 139

3D tisk pro naprosté zelenáče: Co vyrobíte na laciném stroji za pár tisíc korun

3D tisk pro naprosté zelenáče: Co vyrobíte na laciném stroji za pár tisíc korun

** Domácí 3D tisk je dnes už finančně dostupný prakticky všem ** Lacinou tiskárnu pořídíte za pár tisíc korun ** Jak vlastně tisk probíhá a jak navrhnout, co vytisknout

Jakub Čížek | 67


Aktuální číslo časopisu Computer

Megatest 20 procesorů

Srovnání 15 True Wireless sluchátek

Vyplatí se tisknout fotografie doma?

Vybíráme nejlepší základní desky