Acasă Flori perene Dezvoltarea de aplicații client-server folosind Indy în Delphi. Componente Indy utilizate în Delphi. Câteva exemple de utilizare a componentelor Indy

Dezvoltarea de aplicații client-server folosind Indy în Delphi. Componente Indy utilizate în Delphi. Câteva exemple de utilizare a componentelor Indy

Protocolul UDP este destul de bun pentru transferul de mesaje text, adică puteți organiza chat-uri locale și altele asemenea. Am decis să dau un exemplu de cea mai simplă lucru cu UDP în Delphi.

Instrucțiuni pas cu pas:

Ți-am dat un exemplu, dar mă vei ierta, nu am început să descriu fiecare rând, pentru că Nu văd nimic dificil și toată lumea își poate da seama.

De fapt, dacă ceva nu este clar, poți să-mi pui o întrebare. Și iată codul real:

utilizări
Windows, Mesaje, SysUtils, Variante, Clase, Grafică, Controale, Formulare,
Dialogs, StdCtrls, IdUDPServer, IdBaseComponent, IdComponent, IdUDPBase,
IdUDPClient, IdSocketHandle;

tip
TForm1 = clasa (TForm)
IdUDPClient1: TIdUDPClient;
IdUDPServer1: TIdUDPServer;
Buton1: TBbutton;
Label1: TLabel;
procedura FormCreate (Expeditor: TObject);
procedura FormClose (Expeditor: TObject; var Action: TCloseAction);
procedura Buton1Click (Expeditor: TObject);
procedura IdUDPServer1UDPRead (AThread: TIdUDPListenerThread; AData: TBytes;
ABind: TIdSocketHandle);
privat
(Declarații private)
public
(Declarații publice)
Sfârșit;

var
Form1: TForm1;

($ R * .dfm)
[b] // Procedura pentru trimiterea unui mesaj
procedura TForm1.Button1Click (Expeditor: TObject);
începe
încerca
IdUDPClient1.Active: = Adevărat;
IdUDPClient1.Host:= "localhost";
IdUDPClient1.Connect;
dacă IdUDPClient1.Conectat atunci
începe
IdUDPClient1.Send (TimeToStr (Ora));
Label1.Caption: = „ok”;
Sfârșit;
IdUDPClient1.Active: = Fals;
Bip; Bip; Bip;
cu exceptia
MessageDlg ("Ceva a mers prost = (", mtError,, 0);
Sfârșit;
Sfârșit;
[b]
//Pornit oprit. Serverul UDP la pornirea și închiderea formularului
procedura TForm1.FormClose (Expeditor: TObject; var Action: TCloseAction);
începe
IdUDPServer1.Active: = False;
Sfârșit;

procedura TForm1.FormCreate (Expeditor: TObject);
începe
IdUDPServer1.Active: = Adevărat;
Sfârșit;

[b] // Procedura pentru reacția serverului la primirea datelor
procedura TForm1.IdUDPServer1UDPRead (AThread: TIdUDPListenerThread;
AData: TBytes; ABind: TIdSocketHandle);
Var
i: întreg;
s: șir;
începe
s: = "";
încerca
i: = 0;
în timp ce (AData [i] 0) do
începe
s: = s + chr (AData [i]);
i: = i + 1;
Sfârșit;
in cele din urma
Label1.Caption: = s;
Sfârșit;
Sfârșit;

Pe scurt, Indy este o componentă pentru lucrul ușor cu protocoalele populare de Internet. Principiul lor de funcționare se bazează pe utilizarea prizelor de blocare. Indy este interesant și convenabil pentru că este destul de abstract. Și programarea Indy se reduce la programare liniară. Apropo, pe internet este larg răspândit un articol tradus, în care sunt cuvintele „regimul de blocare nu e diavolul” :)) La un moment dat m-a amuzat foarte mult această traducere. Articolul face parte din cartea lui Hoover și Hariri „The Depths of Indy”. Practic, nu trebuie să citești totul pentru a lucra cu Indy, dar tot recomand să te familiarizezi cu principiile protocoalelor Internet. Cât despre regimul „diavolesc”. Un apel de blocare a socketului nu revine de fapt până când își încheie sarcina. Când se fac apeluri pe firul principal, interfața aplicației se poate bloca. Pentru a evita această situație neplăcută, dezvoltatorii indienilor au creat componenta TIdAntiFreeze. Trebuie doar să-l aruncați pe formular și interfața cu utilizatorul se va redesena cu calm în timpul executării apelurilor de blocare.

Probabil că v-ați familiarizat deja cu conținutul diferitelor file „Indy (...)” din Delphi. Există o mulțime de componente și fiecare dintre ele poate fi utilă. Eu însumi nu am lucrat cu toată lumea, deoarece nu văd nevoia să-i studiez fără o sarcină anume.

Distribuția de bază Delphi include Indy v.9 cu un ban. Probabil, este indicat să faceți imediat upgrade la o versiune mai nouă (de exemplu, acum am 10.0.76, dar există și altele ulterioare, cum ar fi).

Există componente client și server care funcționează cu aceleași protocoale. Indy simplifică cu adevărat dezvoltarea aplicațiilor, spre deosebire de dezvoltarea aceleiași funcționalități pe socketuri. De exemplu, pentru a comunica cu serverul, apelați pur și simplu metoda Connect. Stabilirea cu succes a unei conexiuni va fi marcată de o întoarcere de la metodă fără a provoca o excepție. Dacă conexiunea nu este apelată, va fi lansată o excepție.

Exemplu „academic” (codul nu funcționează, nu rulați :)):

Cu IndyClient faceți
începe
Gazdă: = "test.com";
Port: = 2000;
Conectați;
Încerca
// lucrează cu date (citește, scrie...)
in cele din urma
Deconectat;
Sfârșit;
Sfârșit;

Gazda și portul pot fi setate în inspectorul de obiecte sau în timpul execuției.

Deci, pentru ce puteți folosi componentele Indy în sarcinile de analizare? Aplicația este variată! Cel mai simplu lucru este să obțineți conținutul paginii (probabil că toată lumea a întâlnit deja asta) folosind componenta IdHTTP:

Var
rcvrdata: TMemoryStream;
idHttp1: TidHttp;
începe
idHttp1: = TidHttp.Create (nil);
rcvrdata: = TMemoryStream.Create;
idHttp1.Request.UserAgent: = "Mozilla / 4.0 (compatibil; MSIE 5.5; Windows 98)";
idHttp1.Request.AcceptLanguage: = "ru";
idHttp1.Response.KeepAlive: = adevărat;
idHttp1.HandleRedirects: = adevărat;
încerca
idHttp1.Get (Edit1.Text, rcvrdata);
in cele din urma
idHttp1.Free;
Sfârșit;
dacă rcvrdata.Size> 0 atunci începe
ShowMessage („Received” + inttostr (rcvrdata.Size));
rcvrdata.SaveToFile ("c: \ 111.tmp");
Sfârșit;
rcvrdata.Free;
Sfârșit;

După cum puteți vedea, puteți nu numai să obțineți conținutul paginii, ci și să simulați încărcarea unui document de la un anumit client. Componentele Indy sunt în general utile pentru generarea antetelor și a solicitărilor POST. Mai multe despre asta cu exemple data viitoare.

Pentru a fi la curent cu actualizările blogului, poți

Introducere în Indy

Introducere în Indy
Autor: Chad Z. Hower
Pagina principală: http://www.atozedsoftware.com
Traducere: Anatoly Podgoretsky
introducere
Am scris acest articol când versiunea actuală era Indy 8.0. O mare parte din acest articol este aplicabilă și foarte utilă în versiunile viitoare ale Indy. Dacă ți-a plăcut acest articol și ai dori să citești articole mai detaliate, atunci aruncă o privire la cartea Indy in Depth.
Indy se blochează
Indy folosește prize de blocare. Modul de blocare este similar cu citirea/scrierea unui fișier. Când citiți date sau scrieți, funcția nu revine până la sfârșitul operațiunii. Diferența față de lucrul cu fișiere este că apelul poate dura mai mult, deoarece datele solicitate nu sunt încă disponibile, depinde de viteza cu care funcționează rețeaua sau modemul.
De exemplu, un apel de metodă este pur și simplu făcut și așteptați până când controlul este returnat la punctul de invocare. Dacă apelul a avut succes, atunci controlul va fi returnat de la metodă; în caz de eroare, va fi aruncată o excepție.
Modul de blocare nu este fatal
Datorită modului de blocare, am fost bătuți în mod repetat de adversarii noștri, dar modul de blocare nu este diavolul.
Problema a apărut după portarea Winsock pe Windows. În Unix, problema a fost de obicei rezolvată prin bifurcare (pare o mulțime de fire, dar în detrimentul proceselor separate în loc de fire). Clienții și demonii Unix au trebuit să forkeze procesele pentru a rula și a utiliza modul de blocare. Windows 3.x nu a putut fi paralelizat și nu a suportat mult threading. Utilizarea unei interfețe de blocare ar îngheța interfața cu utilizatorul și ar face ca programele să nu răspundă. Prin urmare, la WinSock au fost adăugate moduri neblocante, permițând Windows 3.x, cu limitările sale, să folosească Winsock fără a bloca firul principal și unic al programului. Acest lucru a necesitat programare diferită, Microsoft și alții au denigrat modurile de blocare cu pasiune pentru a ascunde defectele Windows 3.x.
Apoi a venit Win32, care a fost capabil să suporte o mulțime de threading. Dar până în acest moment, creierul era deja pudrat (adică dezvoltatorii considerau că blocarea prizelor este produsul diavolului) și era deja greu să schimbe ceea ce făcuseră. Prin urmare, denigrarea regimurilor de blocare continuă.
În realitate, Unix are doar socket-uri de blocare. Prizele de blocare au, de asemenea, avantajele lor și sunt mult mai bune pentru o mulțime de filetare, securitate și alte aspecte. Mai multe extensii au fost adăugate la Unix pentru socket-uri care nu blochează. Cu toate acestea, funcționează foarte diferit decât pe Windows. Sunt, de asemenea, non-standard și nu foarte frecvente. Socketurile de blocare Unix sunt folosite în aproape toate cazurile și vor continua să fie folosite.
Avantajele modului de blocare · Mai ușor de programat - Modurile de blocare sunt mai ușor de programat. Toate codurile personalizate pot fi într-un singur loc și pot rula într-o ordine naturală, secvenţială. · Mai ușor de portat la Unix - Deoarece Unix folosește socket-uri de blocare, este mai ușor să scrieți cod portabil în acest caz. Indy folosește acest fapt pentru a scrie cod consistent. · Mai bine să lucrați cu fluxuri - Deoarece socketurile de blocare sunt moștenite, acestea sunt foarte ușor de utilizat în fluxuri.
Dezavantajele modului de blocare · UI se blochează în clienți - Apelarea unui socket de blocare nu revine până când își finalizează sarcina. Când un astfel de apel este efectuat pe firul principal al aplicației, aplicația nu poate procesa mesajele utilizatorului. Acest lucru îngheață interfața cu utilizatorul, nu actualizează Windows și alte mesaje nu pot fi procesate până când controlul este returnat de la soclul de blocare.
Componenta TIdAntiFreeze
Indy are o componentă specială care rezolvă problema blocării UI. Doar adăugați o componentă TIdAntiFreeze oriunde în aplicația dvs. și puteți efectua blocarea apelurilor fără a îngheța interfața de utilizare.
TIdAntiFreeze rulează pe un temporizator intern off-stack și apelează Application.ProcessMessages când expiră timpul de expirare. Apelurile externe către Indy continuă să se blocheze și, prin urmare, funcționează în același mod, fără a utiliza componenta TIdAntiFreeze. Folosirea TIdAntiFreeze îți permite să obții toate avantajele blocării prizelor, fără dezavantaje.
Filetat
Codestream-urile sunt aproape întotdeauna folosite cu socket-uri de blocare. Socketurile neblocante pot folosi și fluxuri, dar acest lucru necesită o procesare suplimentară, iar avantajele lor în acest caz se pierd în comparație cu socket-urile de blocare.
Beneficiile fluxurilor · Prioritizare - Prioritățile fluxurilor individuale pot fi configurate. Acest lucru permite mai mult sau mai puțin timp CPU să fie alocat sarcinilor individuale. · Încapsulare - Fiecare conexiune poate conține o aparență de interfață cu o altă conexiune. · Securitate - Fiecare fir poate avea atribute de securitate diferite. · Procesoare multiple — Oferă un avantaj pe sistemele cu procesoare multiple. · Nu este necesară serializarea - oferă concurență completă. Fără multe thread-uri, toate cererile ar trebui procesate într-un singur thread. Prin urmare, fiecare sarcină trebuie împărțită în bucăți mici, astfel încât să poată rula rapid. În timp ce un bloc este în curs de execuție, toate celelalte trebuie să aștepte finalizarea acestuia. La sfârșitul unui bloc, următorul este executat și așa mai departe. Cu multithreading, fiecare sarcină poate fi programată ca o singură unitate, iar sistemul de operare distribuie timpul între toate sarcinile.
Fluxuri de sondaje
Crearea și distrugerea thread-urilor necesită foarte mult resurse. Acest lucru este deosebit de dificil pentru serverele care au conexiuni de scurtă durată. Fiecare server creează un flux, îl folosește pentru o perioadă scurtă de timp și apoi îl distruge. Acest lucru duce la crearea și ștergerea foarte frecventă de fire. Un exemplu în acest sens este un server Web. Se trimite o singură cerere și se returnează un răspuns simplu. Când utilizați un browser, în timp ce navigați pe orice site Web, pot apărea sute de conexiuni și deconectări
Firele de sondare pot rezolva această situație. În loc să creeze și să distrugă fire de execuție la cerere, firele de execuție sunt selectate dintr-o listă de fire neutilizate, dar deja create, din grup. Când firul nu mai este necesar, acesta este returnat în bazin în loc să fie distrus. Threadurile din pool sunt marcate ca neutilizate și, prin urmare, nu consumă timp CPU. Pentru o îmbunătățire și mai mare, fluxurile pot fi ajustate dinamic la nevoile curente ale sistemului.
Indy acceptă fire de sondare. Pool-ul de fire Indy este accesibil prin componenta TIdThreadMgrPool.
Multe fire
Un server foarte încărcat poate necesita sute sau chiar mii de fire. Există o credință comună că sute și mii de fire vă pot distruge sistemul. Aceasta este o credință falsă.
Pe majoritatea serverelor, firele așteaptă date. În timp ce așteptați un apel de blocare, firul este inactiv. Într-un server cu 500 de fire, doar 50 pot fi active în același timp.
Numărul de fire care rulează pe sistemul dumneavoastră vă poate surprinde. Cu numărul minim de servere care rulează și aplicațiile specificate care rulează, sistemul meu are 333 fire create, chiar și cu 333 fire, procesorul este încărcat doar 1%. Un server IIS (Microsoft Internet Information Server) foarte încărcat poate crea sute și mii de fire.
Fluxuri și secțiuni globale
Cu mai multe fluxuri, trebuie să vă asigurați integritatea datelor atunci când le accesați. Acest lucru poate fi dificil pentru programatorii non-threaded. Cu toate acestea, de regulă, majoritatea serverelor nu trebuie să utilizeze date globale. Majoritatea serverelor îndeplinesc funcții izolate. Fiecare fir își îndeplinește propria sarcină izolată. Secțiunile globale de citire/scriere sunt o caracteristică a multor aplicații multithreaded, dar nu tipice pentru servere.
Metodologia Indy
Indy este diferit de orice altă componentă Winsock cu care sunteți obișnuit. Dacă ați lucrat cu alte componente, atunci cea mai bună soluție este să uitați cum funcționează. Multe alte componente folosesc apeluri neblocante (asincrone) și funcționează asincron. Ei trebuie să răspundă la evenimente, să creeze o mașină de stare și, adesea, să aștepte bucle.
De exemplu, cu alte componente, atunci când apelați o conexiune, trebuie fie să așteptați ca evenimentul de conectare să aibă loc, fie să așteptați într-o buclă ca proprietatea să indice că a avut loc conexiunea. Cu Indy, puteți apela metoda Connect și așteptați ca aceasta să revină. Rambursările vor fi făcute dacă conexiunea are succes sau se ridică o excepție dacă există o problemă. Prin urmare, lucrul cu Indy este foarte asemănător cu lucrul cu fișiere. Indy vă permite să puneți tot codul într-un singur loc, în loc să fiți împrăștiat în diferite evenimente. În plus, Indy este foarte simplă și cea mai raționalizată.
Cât de diferită este Indy
Prezentare generală · Blocarea apelurilor este folosită · Nu sunt orientate către evenimente - există evenimente, dar sunt folosite în scop informativ și nu sunt cu adevărat necesare. · Proiectat pentru fire - Indy este conceput pentru fire, cu toate acestea poate fi folosit fără fire. Programare secvențială
Considerare detaliată
Indy nu numai că folosește blocarea apelurilor (sincrone), dar funcționează și așa. O sesiune tipică Indy arată astfel:
cu IndyClient începe
Conectați; Încerca
// Fă-ți lucrurile aici
în cele din urmă Deconectați-vă; Sfârșit;
Sfârșit;
Cu alte componente, arată astfel:
procedura TFormMain.TestOnClick (Expeditor: TComponent);
începe
cu SocketComponent începe
Conectați; încerca
în timp ce nu este conectat, începe
dacă IsError atunci începe
Avorta;
Sfârșit;

OutData: = „Date de trimis”;
în timp ce lungimea (OutData)> 0 începe
Application.ProcessMessages;
Sfârșit;
în cele din urmă Deconectați-vă; Sfârșit;
Sfârșit;
Sfârșit;
procedura TFormMain.OnConnectError;
începe
IsError: = Adevărat;
Sfârșit;
procedura TFormMain.OnRead;
var
i: întreg;
începe
i: = SocketComponent.Send (OutData);
OutData: = Copiere (OutData, i + 1, MaxInt);
Sfârșit;
Multe componente nu fac o treabă foarte bună în izolarea programatorului de stivă. Multe componente, în loc să izoleze utilizatorul de complexitatea stivei, pur și simplu îl lasă singur cu el sau oferă un înveliș peste stivă.
Felul special al lui Indy
Indy este proiectat de la zero pentru a fi multithreaded. Construirea de servere și clienți în Indy este similară cu construirea de servere și clienți în Unix. Aplicațiile Unix apelează de obicei stiva direct cu un strat de abstractizare puțin sau deloc.
De obicei, serverele Unix au unul sau mai mulți ascultători care ascultă cererile primite de la client. Un nou proces este creat pentru fiecare client care trebuie servit. Acest lucru face programarea ușoară, fiecare proces este pentru un singur client. Fiecare proces începe în propriul său context de securitate, care este definit de un ascultător sau de un proces bazat pe drepturile, identitatea sau alte lucruri existente.
Serverele Indy funcționează aproape în același mod. Windows, spre deosebire de Unix, nu poate replica bine procesele, dar funcționează bine cu firele. Serverele Indy creează un fir separat pentru fiecare conexiune client.
Serverele Indy desemnează un fir de ascultare care este separat de firul de cod principal al programului. Firul de ascultare ascultă cererile primite de la clienți. Pentru fiecare client care răspunde, un nou thread este creat pentru a servi clientul. Evenimentele corespunzătoare sunt apoi servite în contextul acestui thread.
Opinie client Indy
Indy este conceput pentru a oferi un nivel foarte ridicat de abstractizare. Confuzia și granularitatea stivei TCP / IP sunt ascunse de programator. De obicei, o sesiune client tipică în Indy arată astfel:
cu IndyClient începe
Gazdă: = "zip.pbe.com"; // Gazdă de apelat
Port: = 6000; // Port pe care să apeleze serverul
Conectați; Încerca
// Fă-ți lucrurile aici
în cele din urmă Deconectați-vă; Sfârșit;
Sfârșit;
Prezentare generală a serverelor Indy
Componentele serverului Indy creează un fir de ascultare care este izolat de firul de cod principal al programului. Firul de ascultare ascultă cererile primite de la clienți. Pentru fiecare client care răspunde, un nou thread este creat pentru a servi clientul. Evenimentele corespunzătoare sunt apoi servite în contextul acestui thread.

Exemple practice
Următoarele exemple ar trebui să vă ajute să începeți cu componente pentru utilizare simplă, dar pentru a demonstra exemplele sunt făcute ca aplicații simple. Unele proiecte sunt realizate pentru a demonstra diferite situații. Aceste exemple sunt disponibile și pentru descărcare ca fișiere zip.
Notă de la traducător: linkul de pe site nu funcționează.
Exemplul 1 - Verificarea codului poștal
Primul proiect a fost realizat cât se poate de simplu. Căutați după codul poștal, clientul întreabă serverul cărui oraș și stat îi aparține codul poștal specificat.
Pentru cei care locuiesc în afara Statelor Unite și nu știu ce este un cod poștal, acesta este codul poștal care indică locul de livrare. Codurile poștale au 5 cifre.
Protocol
Primul pas în construirea unui server și a unui client este dezvoltarea unui protocol. Pentru protocoalele standard, aceasta este definită de RFC-ul corespunzător. Pentru un cod poștal, protocolul este definit mai jos.
Majoritatea protocoalelor de schimb funcționează în modul text. Schimb înseamnă că se transmite o comandă și, ca răspuns, o stare și eventual date. Protocoalele nu se limitează la schimb, dar textul simplu este încă folosit. Protocolul de determinare a codului poștal este de asemenea textual. Textul simplu face protocoalele ușor de depanat și permite comunicarea între diferite limbaje de programare și sisteme de operare.
După conectare, serverul trimite un mesaj de bun venit, apoi primește comanda. Această comandă poate fi „ZipCode x” (Unde x este codul poștal) sau „Ieșire”. Ca răspuns la comanda ZipCode, un răspuns este trimis ca o singură linie cu răspunsul sau o linie goală dacă codul nu este găsit. Comanda Quit face ca serverul să se deconecteze. Serverul poate accepta mai multe comenzi înainte de a trimite comanda Quit.
Cod sursă server

unitate ServerMain;

interfata

utilizări

tip

TformMain = clasa (TForm)

IdTCPServer1: TIdTCPServer;

procedura FormCreate (Expeditor: TObject);

procedura FormDestroy (Expeditor: TObject);

procedura IdTCPServer1Connect (AThread: TIdPeerThread);

privat

ZipCodeList: TStrings;

public

Sfârșit;

FormMain: TformMain;

implementare

(R * .DFM)

procedura TformMain.IdTCPServer1Connect (AThread: TIdPeerThread);

începe

AThread.Connection .WriteLn ("Indy Zip Code Server Ready.");

Sfârșit;

SComandă: șir;

începe

SComand: = ReadLn;

Sfârșit;

Sfârșit;

Sfârșit;

procedura TformMain.FormCreate (Expeditor: TObject);

începe

ZipCodeList: = TStringList.Create;

ZipCodeList.LoadFromFile (ExtractFilePath (Application.EXEName) + „ZipCodes.dat”);

Sfârșit;

procedura TformMain.FormDestroy (Expeditor: TObject);

începe

ZipCodeList.Free;

Sfârșit;

Sfârșit.

Singurele părți specifice Indy din proiect sunt componenta IdTCPServer1, metodele IdTCPServer1Connect și IdTCPServer1Execute.
Formularul conține componenta IdTCPServer1 de tip TIdTCPServer. Următoarele proprietăți au fost modificate: · Active = True - După ce aplicația pornește, serverul ascultă. · DefaultPort = 6000 - Valoarea portului pentru acest proiect. Serverul ascultă cererile clientului pe acest port.
Metoda IdTCPServer1Execute este asociată cu evenimentul OnExecute al serverului. Evenimentul OnExecute este declanșat după ce conexiunea clientului este acceptată. Evenimentul OnExecute este diferit de alte evenimente pe care le cunoașteți. OnExecute este executat în contextul firului de execuție. Evenimentul thread este apelat și argumentul AThread transmis metodei este transmis acestuia. Acest lucru este important deoarece multe evenimente OnExecute pot rula în același timp. Acest lucru este pentru ca serverul să poată funcționa fără a crea o nouă componentă. Există, de asemenea, metode care pot fi înlocuite la construirea descendenților.
Evenimentul OnConnect este apelat după ce conexiunea a fost acceptată și a fost creat un fir pentru acesta. Pe acest server, acesta este folosit pentru a trimite un mesaj de bun venit clientului. Opțional, acest lucru se poate face și în evenimentul OnExecute.
Evenimentul OnExecute poate fi declanșat de mai multe ori până când conexiunea este deconectată sau pierdută. Acest lucru elimină necesitatea de a verifica conexiunea pentru deconectare sau pierderea buclei în cadrul unui eveniment.
IdTCPServer1Execute folosește două funcții de bază, ReadLn și WriteLn. ReadLn citește un șir din conexiune, iar WriteLn trimite un șir la conexiune.
sComandă: = ReadLn;
Codul de mai sus preia un șir de la client și îl plasează în variabila șir locală sCommand.

dacă SameText (sCommand, „QUIT”) atunci începe

se încheie altfel dacă SameText (Copy (sCommand, 1, 8), "ZipCode"), apoi începe

WriteLn (ZipCodeList.Values ​​​​[Copy (sCommand, 9, MaxInt)]);

Sfârșit;


Apoi, sCommand este verificat pentru comenzi valide.
Dacă comanda este „Ieșire”, atunci se execută Deconectare. Nu este permisă citirea sau scrierea după deconectare. După sfârșitul evenimentului, firul de ascultare nu îl mai apelează, ci șterge firul și încheie conexiunea.
Dacă comanda este „ZipCode”, atunci parametrul de după comandă este preluat și tabelul este scanat pentru prezența orașului și a statului. Orașul și statul sunt apoi transmise clientului sau un șir gol este transmis dacă nu există nicio potrivire.
Apoi metoda iese. Serverul va ridica din nou evenimentul de îndată ce sosește o nouă comandă, permițând clientului să trimită mai multe comenzi.
Cod sursă client

unitate ClientMain;

interfata

utilizări

Windows, Mesaje, SysUtils, Clasuri, Grafică, Controale, Formulare, Dialoguri,

StdCtrls, ExtCtrls, IdAntiFreezeBase,

IdAntiFreeze, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient;

tip

TformMain = clasa (TForm)

Client: TIdTCPClient;

IdAntiFreeze1: TIdAntiFreeze;

Panel1: TPanel;

Panel2: TPanel;

MemoInput: TMemo;

LboxResults: TListBox;

Panel3: TPanel;

Buton1: TBbutton;

Button2: TButton;

Label1: TLabel;

procedura Button2Click (Expeditor: TObject);

procedura Buton1Click (Expeditor: TObject);

privat

public

Sfârșit;

FormMain: TformMain;

implementare

(R * .DFM)

procedura TformMain.Button2Click (Expeditor: TObject);

începe

MemoInput.Clear;

LboxResults.Clear;

Sfârșit;

procedura TformMain.Button1Click (Expeditor: TObject);

I: întreg;

S: sfoară;

începe

ButnLookup.Enabled: = adevărat; încerca

LboxResults.Clear;

cu Clientul începe

Conectați; încerca

LboxResults.Items .Add (ReadLn);

pentru i: = 0 la memoInput.Lines .Count - 1 do begin

WriteLn ("ZipCode" + memoInput.Lines [i]);

LboxResults.Items .Add (memoInput.Lines [i]);

S: = ReadLn;

dacă s = "" atunci începe

S: = „- Nu a fost găsită nicio intrare pentru acest cod poștal.”;

Sfârșit;

LboxResults.Items .Add (s);

LboxResults.Items .Add ("");

Sfârșit;

WriteLn ("Ieșire");

în cele din urmă Deconectați-vă; Sfârșit;

Sfârșit;

în sfârșit butnLookup.Enabled: = adevărat; Sfârșit;

Sfârșit;

Sfârșit.


Singurele părți specifice componentei client sunt metoda Button1Click.
Componenta Client de tip TIdTCPClient se află pe formular. Următoarele proprietăți au fost modificate: · Gazdă = 127.0.0.1 - Serverul este situat pe aceeași mașină cu clientul. Port = 6000 - Port server
Metoda Button1Click este asociată cu evenimentul OnClick al componentei Button1. Când se face clic pe butonul, se apelează această metodă. Partea Indy a acestei metode poate fi redusă la următoarele: 1. Conectați-vă la server (Conectați;) 1. Citiți salutul de la server. 1.Pentru fiecare linie introdusă de utilizator în TMemo: 1.Trimiteți o cerere către server (WriteLn ("ZipCode" + memoInput.Lines [i]);) 1.Citiți un răspuns de la server (s: = ReadLn; ) 1.Trimiteți comanda Quit (WriteLn ("Quit");) 1.Deconectați (Deconectați;)
Testare
Acest exemplu a fost testat și funcționează cu TCP/IP instalat. Îl puteți schimba pentru a funcționa în rețea de la un computer la altul. Prin pornirea serverului pe alt computer și schimbarea numelui sau IP-ului serverului pe client.
Pentru a testa proiecte, compilați și rulați serverul. Apoi compilați și rulați clientul. Introduceți codul poștal în câmpul de memorare și apăsați tasta de căutare.
Depanare
Protocoalele bazate pe text sunt foarte ușor de depanat, deoarece pot fi verificate cu Telnet. Pentru a face acest lucru, este suficient să cunoașteți portul serverului. Serverul de căutare cod zip ascultă pe portul 6000.
Lansați din nou serverul de căutare cod zip. Apoi deschideți o consolă (cum ar fi o fereastră Dos). Acum introduceți:
telnet 127.0.0.1 6000
Acum sunteți conectat la server. Unele servere trimit un mesaj de bun venit atunci când fac acest lucru. Unii nu. Nu veți vedea liniile pe care le introduceți. Majoritatea serverelor nu ecou pentru a economisi lățimea de bandă. Cu toate acestea, puteți modifica setările telnet setând parametrul „Echo On”. În diferiți clienți telnet acest lucru se face în moduri diferite, iar unii nu au deloc o astfel de oportunitate. Acum introduceți:
cod poștal 37642
Veți vedea răspunsul serverului:
CHURCH HILL, TN
Pentru a vă deconecta de la server, introduceți:
părăsi
Exemplul 2 - accesarea unei baze de date
Acest exemplu emulează un server care trebuie să efectueze sarcini de blocare, altele decât apelurile de socket. Multe servere sunt forțate să funcționeze în astfel de condiții. Serverele care au nevoie să acceseze baza de date, apelurile către proceduri externe sau calcule de multe ori nu pot întrerupe aceste apeluri, deoarece acestea sunt apeluri externe sau din cauza complexității acestora. Referința la bază nu poate fi împărțită în bucăți mici, iar dezvoltatorul trebuie să aștepte finalizarea operațiunii cu baza. Aceasta este o caracteristică nu numai a apelurilor de baze de date, ci și a altor operațiuni, cum ar fi compresia, calculele și alte procesări de același tip.
În scopuri demonstrative, să presupunem că serverul efectuează un apel la baza de date care durează 5 secunde. Pentru simplitate, să o facem doar cu o pauză, folosiți funcția Sleep (5000) pentru aceasta, în loc să sunați efectiv.
Acest exemplu necesită, de asemenea, mai puține detalii decât exemplul anterior, deoarece multe concepte nu sunt încă înțelese.
Sursă

unitate principală;

interfata

utilizări

Windows, Mesaje, SysUtils, Clasuri, Grafică, Controale, Formulare, Dialoguri,

IdBaseComponent, IdComponent, IdTCPServer;

tip

TformMain = clasa (TForm)

IdTCPServer1: TIdTCPServer;

procedura IdTCPServer1Execute (AThread: TIdPeerThread);

privat

public

Sfârșit;

FormMain: TformMain;

implementare

(R * .DFM)

procedura TformMain.IdTCPServer1Execute (AThread: TIdPeerThread);

I: întreg;

începe

cu AThread.Conexiunea începe

WriteLn ("Bună ziua. Server DB pregătit.");

I: = StrToIntDef (ReadLn, 0);

// Sleep este înlocuit cu un DB lung sau alt apel

Somn (5000);

WriteLn (IntToStr (i * 7));

Sfârșit;

Sfârșit;

Sfârșit.

Deoarece evenimentul Execute are loc în contextul unui fir, codul de procesare poate fi de orice lungime. Fiecare client are propriul thread și nu blochează alți clienți.
Testare
Pentru a testa serverul DB, compilați și rulați-l. Conectați-vă la el folosind Telnet pe portul 6001. Serverul va răspunde cu un mesaj de salut. Introduceți numărul. Serverul va „procesa” cererea dumneavoastră și va răspunde în 5 secunde.

Bună ziua tuturor!

La dezvoltarea următorului proiect Web, a apărut sarcina - să implementeze software-ul client în Delphi, care să transfere date pe server folosind metoda POST. Aplicația trebuie să transmită text și să încarce fișiere pe serverul web.

Implementarea unei astfel de trimiteri de date folosind limbaje de dezvoltare web pe partea de server (de exemplu, PHP) este destul de simplă, dar dacă trebuie să scrieți aplicații, software multi-utilizator care interacționează cu serverul, atunci este deja puțin mai mult complicat. Metoda de conectare directă la baza de date și prin FTP la serverul de la Delphi - nu mai există. nu este sigur, nu este de încredere (schimbarea parolelor, date de conectare etc.) și creează suplimentar. probleme de compatibilitate software la nivelul clientului. Pentru a rezolva problema, am decis să scriu scripturi în PHP (partea server) care vor procesa solicitările POST primite și vor returna rezultatul înapoi către client (aplicația Delphi). Avantajele acestei abordări sunt că toate conexiunile și procesarea datelor au loc pe server, ceea ce este mult mai sigur decât o „conexiune” directă.

După ce a început să „google” s-au oferit o mulțime de informații împrăștiate, în principal pe forumuri, dar toate acestea au fost în bucăți. Un lucru este cert că va fi folosită Indy și anume componenta IdHTTP cu metoda POST implementată. De fapt, totul este simplu, această metodă acceptă doi parametri Url a unei resurse și un DataStream (data stream), ca răspuns returnează rezultatul sub formă de text (poate fi și codul HTML al paginii). Principalul lucru a fost formarea corectă a DataStream (fluxul de date transmise), dar pe parcurs, au apărut capcane suplimentare, și anume codificarea rusă (fie că nu este în regulă). Atunci a început distracția pentru câteva ore de rătăcire în imensitatea rețelei. Una peste alta, destul de vorbărie, să trecem la practica și implementarea software-ului.

Deci programul este simplu. Trebuie să trimită date către server folosind metoda POST, datele conțin „ Titlu " (linie), " Descriere »(Text cu mai multe linii) și fișier grafic (jpg, png, date binare gif). Serverul trebuie să accepte aceste date, să le proceseze, să salveze fișierul grafic pe server și să returneze un răspuns. Ca răspuns, să returnăm aplicația Delphi, același text doar cu adăugarea de etichete și un link către fișierul încărcat. Nimic mai mult.

Să începem cu implementarea părții server (similar cu API-ul site-ului). Deschideți orice editor de text (notepad) și scrieți următorul cod în el:

";) else (ecou" Titlu: Lipsește "."
";) // Verificați datele primite pentru prezența datelor de câmp" conținut "dacă (! Gol ($ _ POST [" conținut "])) (echo" Conținut: ". $ _ POST [" conținut "]. "
";) else (echo" Conținut: lipsește "."
";) // Verificați datele primite pentru prezența fișierului atașat" fișier "dacă (! Gol ($ _ FIȘIERE [" fișier "])) ($ finfo = informație cale ($ _ FIȘIERE [" fișier "] [" nume "]); // obține informații despre fișier (nume, extensie, etc.) // Verificați tipul fișierului în lista de tipuri permise (IMPROVIZARE :)) dacă (stripos ("jpgpnggif", $ finfo ["extensie) "]) == 0) ( echo ">>>>>>> Tip de fișier nevalid<<<<<<<<"; exit; //Если не допустим тип, полностью останавливаем скрипт } $fname = "files/" . "testimgfile." . $finfo["extension"]; //формируем путь и новое имя файла move_uploaded_file($_FILES["file"]["tmp_name"],$fname);//сохраняем временный файл "tmp_name" в файл $fname echo "http://".$_SERVER["HTTP_HOST"]."/".$fname; //возвращаем полный путь к файлу } ?>

Notă! La salvare (prin notepad), trebuie să specificați codificarea „UTF-8”, altfel vor apărea probleme cu afișarea alfabetului chirilic!

Scriptul a încercat să ofere comentarii detaliate. Copiați acest script pe serverul dvs. Web, dacă nu există niciunul, puteți utiliza scriptul meu pentru testare, acesta se află la: http://api..php

Următoarele componente sunt utilizate în aspect: Etichetă, Buton (2 buc), Editare (2 buc), Memo (2 buc), CheckBox, OpenDialog, IdHTTP. Denumiți următoarele componente (proprietatea „ Nume”):

  1. Editare (titlu) - Nume = titlu;
  2. Editați (calea fișierului) Nume = imgfile;
  3. Memo (Cuprins)Nume = continut;
  4. Notă (rezultat) - Nume = răspuns;
  5. Buton (...) - Nume = chkfile;
  6. Buton (POST) - Nume = PostBut;
  7. OpenDialog (dialog de selectare a fișierelor) - Nume = PictDialog;

Lăsați IdHTTP1 și CheckBox1 neschimbate (obosite! :)))).

Pentru a nu face întâmplător" Editați | ×»Cale pentru editare ( imgfile), setați proprietatea ReadOnly la True. De asemenea, la imgfileși chkfile setați proprietatea Enabled la false. Le vom activa folosind CheckBox, de exemplu. vă vom oferi posibilitatea de a alege dacă să încărcați sau nu o imagine.

Pentru OpenDialog ( PictDialog), trebuie să setați filtrul (proprietatea Filter) după cum urmează:

Pregătirea vizuală propriu-zisă s-a încheiat! Să începem să codificăm!

În proiect, vom forma un flux de date folosind tipul care vine cu Indy - TidMultiPartFormDataStream. Deși au existat variante de implementare pe TStream, dar lucrează cu TidMultiPartFormDataStream - mai simplu!

Pentru a face acest tip disponibil pentru proiectul nostru, trebuie să adăugați următoarea bibliotecă la Utilizări: IdMultipartFormData.

Pentru CheckBox1, creați un eveniment OnClick (făcând dublu clic pe obiect) și adăugați următorul cod la acest eveniment:

Procedura TForm1.CheckBox1Click (Expeditor: TObject); începe // face calea fișierului și butoanele de dialog active sau inactive imgfile.Enabled: = CheckBox1.Checked; chkfile.Enabled: = CheckBox1.Checked; Sfârșit;

Aici activăm obiectele imgfile șichkfileîn funcție de prezența unei casete de selectare (dacă caseta de selectare este bifată, obiectele devin active).

Acum vom organiza selecția imaginii. Pentru a face acest lucru, creați un eveniment OnClick pe buton chkfile(tot prin dublu clic pe obiect) și scrieți următoarele:

Procedura TForm1.chkfileClick (Expeditor: TObject); începe // deschide un dialog și introduceți calea completă către fișier în imgfile (TEdit) dacă PictDialog.Execute apoi imgfile.Text: = PictDialog.FileName; Sfârșit;

Acest eveniment va declanșa un dialog de selecție a imaginii și dacă utilizatorul face clic pe „ Deschis", Apoi calea către acest fișier va fi adăugată la imgfile.

Și acum ajungem la butonul final „POST”. Creați un eveniment OnClick pentru acest buton și adăugați următorul cod:

Procedura TForm1.PostButClick (Expeditor: TObject); var dataPost: TIdMultiPartFormDataStream; începe dataPost: = TIdMultiPartFormDataStream.Create; dataPost.AddFormField ("titlu", title.Text, "utf-8"). ContentTransfer: = "8bit"; dataPost.AddFormField („conținut”, conținut.Text, „utf-8”). ContentTransfer: = „8bit”; dacă CheckBox1.Checked și (trim (imgfile.Text) = "") atunci // verificați dacă un fișier este selectat sau nu începe ShowMessage ("Trebuie să selectați un fișier grafic!"); Ieșire; Sfârșit; dacă CheckBox1.Checked, atunci dataPost.AddFile ("fișier", imgfile.Text, ""); // adăugați un câmp cu fișierul răspuns.Text: = StringReplace (idHTTP1.Post ("http: //api..php", dataPost), "
", # 13 # 10,); datapost.Free; final;

Deci, în ordine (deși există comentarii):

Datapost - obiect de tip TIdMultiPartFormDataStream. Permite formarea unei structuri de solicitare POST constând din câmpuri de diferite tipuri.

dataPost . AddFormField (" titlu ", titlu . Text ," utf -8 "). Transfer de conținut := " 8 pic "; - adaugă un câmp numit „title” la DataPost, o valoare din „title.Text”, setează codificarea datelor transmise „utf-8” (parametrul este opțional, dar fără indicarea lui explicită, se transmite alfabetul chirilic prin semne de întrebare „?”) Și o metodă foarte importantă „ContentTransfer”. Fără această metodă, datele sunt trimise către server " abracadabra". Vă rugăm să rețineți că numele câmpului ("titlu") de pe partea de transmisie trebuie să corespundă cu numele specificat în script: $ _POST ["titlu"].

Datele din câmpul „conținut” sunt transmise în același mod.

dataPost . Adauga fisier (" fişier ", imgfile . Text ,"") - cu această linie formăm un flux cu date din fișier.

Gata, datele sunt formate, rămâne să le transferați în scriptul de pe server și să obțineți răspunsul:

response.Text: = StringReplace (idHTTP1.Post ("http: //api..php", dataPost), "
",#13#10,);

de cand TMemo nu înțelege eticheta de întrerupere de linie "
", Vom folosi funcția" "pentru a o înlocui cu caracterele de înțeles de întrerupere de linie" # 13 # 10 ".

După finalizarea tuturor, ștergeți memoria din obiectul DataPost cu linia:

datapost.Free;

Deși în exemplul nostru acest lucru se va întâmpla automat la sfârșitul procedurii, dar totuși ...

Rezultatul real al programului pe ecran:

Astfel, putem trimite orice date, fișiere către server, procesăm aceste date pe server și informăm aplicația cu un răspuns, rezultatul execuției scriptului. Poate fi chiar doar 0 sau 1, ceea ce va semnala reacția ulterioară a aplicației.

Tot. Noroc tuturor. Sper că informațiile au fost utile și că le vei găsi o utilizare.

Puteți descărca exemplul și scriptul terminat.

Cod modul complet:

Unitatea PostUnit; interfața folosește Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPConnection, IdTCPConnection, IdTCPConnection IdHTTP, IdMultipartFormData, Vcl.ExtDlgs; tip TForm1 = clasa (TForm) IdHTTP1: TIdHTTP; titlu: TEdit; continut: TMemo; PostBut: TButton; răspuns: TMemo; Label1: TLabel; Label2: TLabel; Label3: TLabel; imgfile: TEdit; chkfile: TButton; Label4: TLabel; CheckBox1: TCheckBox; PictDialog: TOpenDialog; procedura PostButClick (Expeditor: TObject); procedura chkfileClick (Expeditor: TObject); procedura CheckBox1Click (Expeditor: TObject); private (Declarații private) public (Declarații publice) end; var Form1: TForm1; procedura de implementare ($ R * .dfm) TForm1.CheckBox1Click (Expeditor: TObject); începe // face calea fișierului și butoanele de dialog active sau inactive imgfile.Enabled: = CheckBox1.Checked; chkfile.Enabled: = CheckBox1.Checked; Sfârșit; procedura TForm1.chkfileClick (Expeditor: TObject); începe // deschide un dialog și introduceți calea completă către fișier în imgfile (TEdit) dacă PictDialog.Execute apoi imgfile.Text: = PictDialog.FileName; Sfârșit; procedura TForm1.PostButClick (Expeditor: TObject); var dataPost: TIdMultiPartFormDataStream; începe dataPost: = TIdMultiPartFormDataStream.Create; dataPost.AddFormField ("titlu", title.Text, "utf-8"). ContentTransfer: = "8bit"; dataPost.AddFormField („conținut”, conținut.Text, „utf-8”). ContentTransfer: = „8bit”; dacă CheckBox1.Checked și (trim (imgfile.Text) = "") atunci // verificați dacă un fișier este selectat sau nu începe ShowMessage ("Trebuie să selectați un fișier grafic!"); Ieșire; Sfârșit; dacă CheckBox1.Checked, atunci dataPost.AddFile ("fișier", imgfile.Text, ""); // adăugați un câmp cu fișierul răspuns.Text: = StringReplace (idHTTP1.Post ("http: //api..php", dataPost), "
", # 13 # 10,); datapost.Free; sfârşit; sfârşit.

Indy este un pachet de componente destul de puternic care vă permite să dezvoltați diverse aplicații de rețea. În acest tutorial vă voi arăta cum puteți crea aplicații client/server folosind componentele TIdTCPClient și TIdTCPServer.

În primul rând, aș dori să subliniez două avantaje importante ale acestor componente. Cel mai important dintre ele este multithreading-ul, ceea ce înseamnă că serverul creează un fir separat pentru fiecare client, iar acest lucru afectează cu siguranță performanța programului server pe computerele cu procesor multi-core. Al doilea beneficiu este ușurința în utilizare. Este nevoie de 10-20 de linii de cod pentru a scrie cea mai simplă aplicație client-server. Acest pachet de componente este prezent în ansamblurile standard Delphi.

Să scriem un program simplu pentru a trimite un mesaj text de la un client la un server. Să începem să creăm un server.
Plasați componenta IdTCPServer din fila „Servere Indy” din formular. Vom efectua toate setările acestei componente în timpul rulării în evenimentul OnCreate din formularul:
IdTCPServer1.DefaultPort: = 12345;
IdTCPServer1.Activ: = adevărat;
Totul este simplu aici - indicăm portul pe care va funcționa serverul și activăm serverul în sine.

Pentru a primi date pe server de la client, există un eveniment special „OnExecute”. Acest eveniment arată astfel:

începe
Sfârșit;

Să edităm conținutul evenimentului după cum urmează:
procedura TForm3.IdTCPServer1Execute (AContext: TIdContext);
var
l: sfoară; // variabilă șir în care vom primi
începe
l: = AContext.Connection.IOHandler.ReadLn ();
Memo1.Lines.Add (l);
Sfârșit;

Acum, de îndată ce un mesaj ajunge la server, îl vom scrie în variabila șir l și îl vom trimite într-un câmp de text cu mai multe linii.

Pe aceasta, în mod surprinzător, se încheie crearea serverului. Indy va face restul pentru noi. Să începem cu programul client. Se va conecta la server, îi va trimite un mesaj și se va deconecta de la server.

Să creăm un nou proiect, să plasăm componenta IdTCPClient pe formular, care poate fi găsit în fila „Clienți Indy”. De asemenea, vom plasa o editare simplă și un buton. Să creăm un handler de evenimente OnClick pentru butonul, în interiorul căruia scriem:
IdTCPClient1.Port: = 12345;
IdTCPClient1.Host:= '127.0.0.1';
IdTCPClient1.Connect;
IdTCPClient1.IOHandler.WriteLn (Edit1.Text);
IdTCPClient1.Deconectare;

Acest cod nu trebuie să fie plasat în evenimentul OnCreate. Puteți plasa acest cod oriunde doriți.
În prima linie, atribuim un port și trebuie să specificăm același port pe care l-am indicat în programul server, altfel clientul pur și simplu nu va găsi serverul. Apoi indicăm adresa IP a serverului. Serverul în sine poate fi localizat atât în ​​rețeaua locală, cât și de la distanță. În acest din urmă caz, conexiunea se va face prin Internet și va trebui să specificați adresa IP pe Internet.

Am specificat adresa „127.0.0.1”, ceea ce înseamnă că serverul este computerul pe care rulează clientul. Această metodă este foarte convenabilă pentru testarea aplicațiilor de rețea.
Apoi ne conectăm, trimitem un mesaj și ne deconectăm.La fel ca mesajul în sine, puteți lua adresa IP din Editare sau din orice variabilă șir.

Lucrarea la programul client este de asemenea terminată. După cum puteți vedea, Indy face o treabă extraordinară pentru noi, ceea ce face posibil chiar și pentru un programator fără experiență să își creeze propria aplicație de rețea.

Nou pe site

>

Cel mai popular