Hem Fleråriga blommor Utveckling av klient-serverapplikationer med Indy i Delphi. Indy-komponenter som används i Delphi. Några exempel på användning av Indy-komponenter

Utveckling av klient-serverapplikationer med Indy i Delphi. Indy-komponenter som används i Delphi. Några exempel på användning av Indy-komponenter

UDP-protokollet är ganska bra för överföring textmeddelanden, det vill säga du kan organisera lokala chattar och liknande saker. Jag bestämde mig för att ge ett exempel på det enklaste arbetet med UDP i Delphi.

Steg-för-steg-instruktion:

Jag gav ett exempel, men förlåt mig, jag skrev inte ner varje rad, för... Jag ser inget komplicerat och vem som helst kan lista ut det.

Om något är oklart kan du faktiskt ställa en fråga till mig. Och här är den faktiska koden:

använder
Windows, meddelanden, SysUtils, varianter, klasser, grafik, kontroller, formulär,
Dialoger, StdCtrls, IdUDPServer, IdBaseComponent, IdComponent, IdUDPBase,
IdUDPClient, IdSocketHandle;

typ
TForm1 = klass(TForm)
IdUDPClient1: TIdUDPClient;
IdUDPServer1: TIdUDPServer;
Knapp1: TBnapp;
Etikett1: TLabel;
procedure FormCreate(Avsändare: TObject);
procedure FormClose(Avsändare: TObject; var Action: TCloseAction);
procedure Button1Click(Avsändare: TObject);
procedur IdUDPServer1UDPRead(ATråd: TIdUDPListenerThread; AData: TBytes;
ABinding: TIdSocketHandle);
privat
(Privata deklarationer)
offentlig
(Offentliga deklarationer)
slutet;

var
Form1: TForm1;

($R *.dfm)
[b]//Procedur för att skicka ett meddelande
procedure TForm1.Button1Click(Avsändare: TObject);
Börja
Prova
IdUDPClient1.Active:= Sant;
IdUDPClient1.Host:= "localhost";
IdUDPClient1.Connect;
om IdUDPClient1.Connected då
Börja
IdUDPClient1.Send(TimeToStr(Time));
Label1.Caption:= "ok";
slutet;
IdUDPClient1.Active:= False;
Beep;Beep;Beep;
bortsett från
MessageDlg("Något gick fel =(", mtError, , 0);
slutet;
slutet;
[b]
//På av. UDP-server vid start och stängning av formuläret
procedure TForm1.FormClose(Avsändare: TObject; var Action: TCloseAction);
Börja
IdUDPServer1.Active:= Falskt;
slutet;

procedur TForm1.FormCreate(Avsändare: TObject);
Börja
IdUDPServer1.Active:= Sant;
slutet;

[b]//Serverreaktionsprocedur vid mottagning av data
procedur TForm1.IdUDPServer1UDPRead(ATråd: TIdUDPListenerThread;
AData: TBytes; ABinding: TIdSocketHandle);
Var
i:Heltal;
s:Sträng;
Börja
s:= "";
Prova
i:= 0;
medan (AData[i] 0) gör
Börja
s:= s + chr(AData[i]);
i:= i + 1;
slutet;
till sist
Label1.Caption:= s;
slutet;
slutet;

I ett nötskal är Indy komponenter för bekvämt arbete med populära Internetprotokoll. Principen för deras funktion är baserad på användningen av uttag i blockeringsläge. Indy är intressant och bekvämt eftersom det är ganska abstrakt. Och programmering i Indy handlar om linjär programmering. Förresten, en översatt artikel är allmänt spridd på Internet, där det finns orden "blockeringsläget är inte djävulen" :)) En gång var jag väldigt road av den här översättningen. Artikeln är en del av boken "Depths of Indy" av Hoover och Hariri. I princip behöver du inte läsa allt för att arbeta med Indy, men jag rekommenderar ändå att du bekantar dig med principerna för hur internetprotokoll fungerar. När det gäller den "djävulska" regimen. Ett blockerande socketanrop ger faktiskt inte tillbaka kontroll förrän det har slutfört sin uppgift. När samtal görs på huvudtråden kan applikationsgränssnittet låsa sig. För att undvika denna obehagliga situation skapade indiska utvecklare komponenten TIDAntiFreeze. Du behöver bara slänga det på formuläret - och användargränssnittet ritas enkelt om samtidigt som du ringer blockerande samtal.

Du har förmodligen redan blivit bekant med innehållet i de olika "Indy (...)"-flikarna i Delphi. Det finns många komponenter där, och var och en av dem kan vara användbar. Jag har själv inte arbetat med alla, för jag ser inte behovet av att studera dem utan en specifik uppgift.

Den grundläggande Delphi-distributionen inkluderar Indy v.9 med pennies. Det skulle förmodligen vara tillrådligt att omedelbart uppgradera till fler ny version(Jag har till exempel för närvarande 10.0.76, men det finns också senare, verkar det som).

Det finns klient- och serverkomponenter för att arbeta med samma protokoll. Indy förenklar verkligen applikationsutveckling, till skillnad från möjligheten att utveckla samma funktionalitet på sockets. Till exempel, för att upprätta en anslutning med servern, bör du helt enkelt anropa Connect-metoden. En lyckad anslutning kommer att markeras av metoden som returnerar utan att orsaka ett undantag. Om anslutningen inte upprättas kommer ett undantag att skapas.

"Akademiskt" exempel (koden fungerar inte, kör den inte :)):

Med IndyClient gör
Börja
Host:= "test.com";
Port:= 2000;
Ansluta;
Prova
// arbeta med data (läs, skriv...)
till sist
Koppla ifrån;
slutet;
slutet;

Värd och port kan ställas in i objektinspektören eller under körning.

Varför kan du använda Indy-komponenter för att analysera uppgifter? Olika användningsområden! Det enklaste är att få sidans innehåll (alla har förmodligen redan stött på detta) med hjälp av IdHTTP-komponenten:

Var
rcvrdata: TMemoryStream;
idHttp1: TidHttp;
Börja
idHttp1:= TidHttp.Create(noll);
rcvrdata:= TMemoryStream.Create;
idHttp1.Request.UserAgent:= "Mozilla/4.0 (kompatibel; MSIE 5.5; Windows 98)";
idHttp1.Request.AcceptLanguage:= "ru";
idHttp1.Response.KeepAlive:= sant;
idHttp1.HandleRedirects:= true;
Prova
idHttp1.Get(Edit1.Text, rcvrdata);
till sist
idHttp1.Free;
slutet;
om rcvrdata.Size > 0 så börja
ShowMessage("Mottagna" + inttostr(rcvrdata.Size));
rcvrdata.SaveToFile("c:\111.tmp");
slutet;
rcvrdata.Free;
slutet;

Som du kan se kan du inte bara få innehållet på sidan, utan också simulera att ladda ett dokument från en specifik klient. Indy komponenter i allmänhet bekvämt för att generera rubriker och POST-förfrågningar. Mer om detta med exempel nästa gång.

För att hålla dig uppdaterad med blogguppdateringar kan du

Introduktion till Indy

Introduktion till Indy
Upplagt av Chad Z. Hower
Hemsida: http://www.atozedsoftware.com
Översättning: Anatoly Podgoretsky
introduktion
Jag skrev den här artikeln när den nuvarande versionen var Indy 8.0. Mycket av den här artikeln är tillämplig och mycket användbar i framtida versioner av Indy. Om du gillade den här artikeln och vill läsa mer djupgående artiklar, kolla in boken Indy in Depth.
Indy körs i blockeringsläge
Indy använder blockerande uttag. Blockeringsläge liknar fil läs-skriv. Vid läsning eller skrivning av data återställer funktionen inte kontroll förrän operationen är klar. Skillnaden mot att arbeta med filer är att samtalet kan ta längre tid, eftersom de begärda uppgifterna inte finns ännu, detta beror på hastigheten som ditt nätverk eller modem fungerar med.
Till exempel anropas en metod helt enkelt och väntar tills kontroll återgår till larmpunkten. Om samtalet lyckades kommer kontrollen att returneras från metoden, om ett fel uppstår kommer ett undantag att göras.
Lockdown är inte dödlig
På grund av blockeringsläget har vi blivit slagen många gånger av våra motståndare, men blockeringsläget är inte djävulen.
Problemet uppstod efter portering av Winsock till Windows. I Unix löstes problemet vanligtvis genom gaffel (liknande multi-threading, men på bekostnad av individuella processer istället för strömmar). Unix-klienter och demoner var tvungna att dela processerna som skulle köras och använda blockeringsläge. Windows 3.x kunde inte parallelliseras och stödde inte mycket trådning. Användning av ett blockerande gränssnitt frös användargränssnittet och gjorde att program inte svarade. Därför lades icke-blockerande lägen till i WinSock, vilket gjorde att Windows 3.x med dess begränsningar kunde använda Winsock utan att blockera programmets huvud- och enda tråd. Detta krävde annan programmering, Microsoft och andra förtalade passionerat blockeringsregimer för att gömma sig Windows nackdelar 3.x.
Sedan kom Win32, som kunde stödja multi-threading. Men vid det här laget var deras hjärnor redan röriga (det vill säga utvecklarna ansåg att blockering av uttag var djävulens skapelse), och det var redan svårt att ändra vad de hade gjort. Därför fortsätter smutskastningen av blockerande regimer.
I verkligheten har Unix bara blockerande uttag. Blockerande uttag har också sina fördelar och är mycket bättre för multi-threading, säkerhet och andra aspekter. Vissa tillägg har lagts till i Unix för icke-blockerande uttag. De fungerar dock väldigt annorlunda än på Windows. De är också icke-standardiserade och inte särskilt vanliga. Blockerande uttag i Unix används i nästan alla fall, och kommer att fortsätta att användas.
Fördelar med blockeringsläge·Lättare att programmera - Blockeringslägen är lättare att programmera. All användarkod kan finnas på ett ställe och exekveras i en naturlig, sekventiell ordning. Enklare att överföra till Unix - Eftersom Unix använder blockerande uttag, skriv in den bärbara koden I detta fall lättare. Indy använder detta faktum för att skriva enhetlig kod. ·Det är bekvämare att arbeta med trådar - Eftersom blockerande uttag har en sekvens förvärvad av ärftlighet, så de är mycket lätta att använda i trådar.
Nackdelar med blockeringsläge · Användargränssnittet fryser i klienter - Ett blockerande socketanrop ger inte tillbaka kontroll förrän det har slutfört sin uppgift. När ett sådant anrop görs på applikationens huvudtråd kan applikationen inte behandla användarmeddelanden. Detta gör att användargränssnittet fryser, att fönster inte uppdateras och inga andra meddelanden bearbetas förrän kontrollen återställs från den blockerande uttaget.
TIDAntiFreeze-komponent
Indy har en speciell komponent som löser frysproblemet användargränssnitt. Lägg bara till en TIDAntiFreeze-komponent var som helst i din applikation och du kan ringa blockerande samtal utan att frysa användargränssnittet.
TIDAntiFreeze körs på en intern timer utanför samtalsstacken och anropar Application.ProcessMessages när timeouten går ut. Externa anrop till Indy fortsätter att blockera och fungerar därför precis som utan att använda TIdAntiFreeze-komponenten. Genom att använda TIdAntiFreeze kan du få alla fördelar med att blockera uttag, utan några av nackdelarna.
Kodtrådar (trådning)
Med blockerande uttag används kodströmmar nästan alltid. Icke-blockerande sockets kan också använda gängor, men detta kräver ytterligare bearbetning och deras fördelar går förlorade jämfört med blockerande sockets.
Fördelar med trådar·Ställa in prioriteringar - Prioriteringarna för enskilda trådar kan konfigureras. Detta gör att enskilda uppgifter kan allokeras mer eller mindre CPU-tid. ·Inkapsling - Varje anslutning kan innehålla något sken av ett gränssnitt med en annan anslutning. ·Säkerhet - Varje tråd kan ha olika säkerhetsattribut. ·Flera processorer - ger en fördel på system med flera processorer. · Inget behov av serialisering - ger full samtidighet. Utan mycket trådning måste alla förfrågningar behandlas i en tråd. Därför måste varje uppgift delas upp i små bitar så att den kan fungera snabbt. Medan ett block körs tvingas alla andra vänta på att det ska slutföra. I slutet av ett block exekveras nästa och så vidare. Med multithreading kan varje uppgift programmeras som en enda enhet och operativ system fördelar tid mellan alla uppgifter.
Omröstningstrådar
Att skapa och förstöra trådar är mycket resurskrävande. Detta är en särskilt svår uppgift för servrar som har kortlivade anslutningar. Varje server skapar en tråd, använder den en kort tid och sedan förstör det. Detta resulterar i att trådar skapas och tas bort mycket ofta. Ett exempel på detta är en webbserver. En enda begäran skickas och ett enkelt svar returneras. När du använder en webbläsare kan hundratals anslutningar och avbrott inträffa när du tittar på vilken webbplats som helst.
Omröstningstrådar kan korrigera denna situation. Istället för att skapa och förstöra trådar på begäran, väljs trådar från en lista med oanvända men redan skapade trådar från poolen. När en tråd inte längre behövs återförs den till poolen istället för att förstöras. Trådar i poolen är markerade som oanvända och förbrukar därför inte CPU-tid. För mer mer förbättring trådar kan dynamiskt anpassa sig till systemets nuvarande behov.
Indy stöder trådundersökning. Trådpoolen i Indy är tillgänglig via TIdThreadMgrPool-komponenten.
Många trådar
En tungt laddad server kan kräva hundratals eller till och med tusentals trådar. Det finns en vanlig uppfattning att hundratals och tusentals trådar kan döda ditt system. Detta är en falsk tro.
På de flesta servrar väntar trådar på data. Medan du väntar på ett blockerande samtal är tråden inaktiv. I en server med 500 trådar kan endast 50 vara aktiva samtidigt.
Antalet trådar som körs på ditt system kan överraska dig. På minsta kvantitet kör servrar och de angivna körande applikationerna har mitt system 333 trådar skapade, även med 333 trådar är processorn bara 1% laddad. Tungt laddad IIS-server ( Microsoft Internet Information Server) kan skapa hundratals och tusentals trådar.
Trådar och globala avsnitt
Med flera trådar måste du säkerställa dataintegritet när du kommer åt den. Detta kan vara svårt för programmerare som inte har arbetat med trådar. Men i allmänhet behöver de flesta servrar inte använda global data. De flesta servrar utför isolerade funktioner. Varje tråd utför sin egen isolerade uppgift. Globala läs/skrivsektioner är en funktion i många flertrådade applikationer, men är inte typiska för servrar.
Metodik Indy
Indy skiljer sig från andra Winsock-komponenter du är van vid. Om du har arbetat med andra komponenter, då den bästa lösningen kommer att glömma hur de fungerar. Många andra komponenter använder icke-blockerande (asynkrona) samtal och fungerar asynkront. De måste reagera på händelser, skapa en tillståndsmaskin och köra frekventa vänteloopar.
Till exempel, med andra komponenter, när du anropar en anslutning måste du antingen vänta på att anslutningshändelsen inträffar eller vänta i en slinga på att en egenskap indikerar att anslutningen har inträffat. Med Indy kan du anropa Connect-metoden och vänta tills den kommer tillbaka. En återbetalning kommer att utfärdas om anslutningen lyckas eller om ett undantag görs om det finns ett problem. Att arbeta med Indy är därför mycket likt att arbeta med filer. Indy låter dig lägga all din kod på ett ställe, istället för att sprida den överallt olika evenemang. Dessutom är Indy väldigt enkelt och bekvämast när man arbetar med trådar.
Hur annorlunda är Indy?
Kort översikt · Blockerande samtal används · Ej händelseorienterade - det finns händelser, men de används för informationsbehov och är egentligen inte nödvändiga. · Designad för trådar - Indy är designad för trådar, men kan användas utan trådar. Sekventiell programmering
Detaljerad recension
Indy använder inte bara blockerande samtal (synkront) utan fungerar också så här. En typisk Indy-session ser ut så här:
med IndyClient börjar
Ansluta; Prova
// Gör dina saker här
slutligen Koppla bort; slutet;
slutet;
Med andra komponenter ser det ut så här:
procedur TFormMain.TestOnClick(Avsändare: TComponent);
Börja
med SocketComponent börjar
Ansluta; Prova
medan den inte är ansluten börjar
om IsError börja då
Avbryta;
slutet;

OutData:= "Data att skicka";
medan length(OutData) > 0 börjar
Application.ProcessMessages;
slutet;
slutligen Koppla bort; slutet;
slutet;
slutet;
procedur TFormMain.OnConnectError;
Börja
IsError:= Sant;
slutet;
procedur TFormMain.OnRead;
var
i: heltal;
Börja
i:= SocketComponent.Send(OutData);
OutData:= Copy(OutData, i + 1, MaxInt);
slutet;
Många komponenter gör inte ett särskilt bra jobb med att isolera programmeraren från stacken. Många komponenter, istället för att isolera användaren från stackens komplexitet, lämnar helt enkelt användaren åt det eller tillhandahåller ett omslag över stapeln.
Indy speciellt sätt
Indy är designad från grunden för att vara flertrådig. Att bygga servrar och klienter i Indy liknar att bygga servrar och klienter i Unix. Unix-applikationer anropar vanligtvis stacken direkt med lite eller inget abstraktionslager.
Vanligtvis har Unix-servrar en eller flera lyssningsprocesser som övervakar inkommande klientförfrågningar. För varje kund som behöver betjänas, a ny process. Detta gör programmeringen enkel, varje process för endast en klient. Varje process löper för sig eget sammanhang säkerhet, som specificeras av lyssnarprocessen eller processen utifrån befintliga rättigheter, identifiering eller annat.
Indy-servrar fungerar ungefär på samma sätt. Windows, till skillnad från Unix, kan inte multiplicera processer bra, men det fungerar bra med trådar. Indy-servrar skapar en separat tråd för varje klientanslutning.
Indy-servrar tilldelar en lyssningstråd som är skild från programmets huvudkodtråd. Lyssningstråden lyssnar efter inkommande förfrågningar från klienter. För varje klient som den svarar på, a ny tråd för kundtjänst. Motsvarande händelser servas sedan i sammanhanget för den tråden.
Indy kundrecension
Indy är designad för att ge mycket hög nivå abstraktioner. TCP/IP-stackens krånglighet och detaljer är dolda för programmeraren. Vanligtvis ser en typisk klientsession i Indy ut så här:
med IndyClient börjar
Host:= "zip.pbe.com"; // Värd att ringa
Port:= 6000; // Port att anropa servern på
Ansluta; Prova
// Gör dina saker här
slutligen Koppla bort; slutet;
slutet;
Indy serveröversikt
Indy-serverkomponenter skapar en lyssningstråd som är isolerad från huvudprogrammets kodtråd. Lyssningstråden lyssnar efter inkommande förfrågningar från klienter. För varje klient som den svarar på skapas en ny tråd för att betjäna klienten. Motsvarande händelser servas sedan i sammanhanget för den tråden.

Praktiska exempel
Följande exempel bör hjälpa dig att komma igång med komponenter för lätt att använda, men för att visa exempel gjorda som enkla applikationer. Vissa projekt är gjorda i demonstrationssyfte olika situationer. Dessa exempel är också tillgängliga för nedladdning som zip-filer.
Anmärkning från översättaren: länken på webbplatsen fungerar inte.
Exempel 1 - Postnummerverifiering
Det första projektet är gjort så enkelt som möjligt. Sök efter postnummer, klienten frågar servern vilken stad och delstat det angivna postnumret tillhör.
För de som bor utanför USA och inte vet vad ett postnummer är, är det ett postnummer som anger leveransplatsen. Postnummer består av 5 siffror.
Protokoll
Det första steget i att bygga en server och klient är att utveckla ett protokoll. För standardprotokoll definieras detta av motsvarande RFC. För postnummer definieras protokollet nedan.
De flesta kommunikationsprotokoll fungerar i textläge. Exchange innebär att ett kommando sänds och som svar status och eventuellt data. Protokollen är inte begränsade till utbyte utan vanlig text används fortfarande. Även protokollet för att fastställa postnummer är textbaserat. Oformaterad text gör protokoll lätta att felsöka och möjliggör kommunikation olika språk programmering och operativsystem.
Efter anslutning skickar servern ett hejmeddelande och accepterar sedan kommandot. Detta kommando kan vara "Postnummer x" (där x är postnumret) eller "Avsluta". Som svar på ZipCode-kommandot skickas ett svar i form av en rad med svaret eller en tom rad om koden inte hittas. Kommandot Quit får servern att stänga anslutningen. Servern kan acceptera flera kommandon innan kommandot Quit skickas.
Serverns källkod

enhet ServerMain;

gränssnitt

använder

typ

TformMain = klass(TForm)

IdTCPServer1: TIdTCPServer;

procedure FormCreate(Sender: TObject );

procedure FormDestroy(Avsändare: TObject ) ;

procedure IdTCPServer1Connect(AThread: TIdPeerThread) ;

privat

ZipCodeList: TStrings;

offentlig

slutet ;

FormMain: TformMain;

genomförande

(R*.DFM)

procedur TformMain.IdTCPServer1Connect (AThread: TIdPeerThread) ;

Börja

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

slutet ;

SCommand: sträng ;

Börja

SCommand:= ReadLn ;

slutet ;

slutet ;

slutet ;

procedure TformMain.FormCreate (Avsändare: TObject );

Börja

ZipCodeList:= TStringList.Create ;

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

slutet ;

procedur TformMain.FormDestroy (Avsändare: TObject );

Börja

ZipCodeList.Free ;

slutet ;

slutet.

De enda Indy-specifika delarna i projektet är IdTCPServer1-komponenten, IdTCPServer1Connect och IdTCPServer1Execute-metoderna.
Formuläret innehåller IdTCPServer1-komponenten av typen TIdTCPServer. Följande egenskaper har ändrats: ·Active = True - När programmet startar lyssnar servern. DefaultPort = 6000 - Portvärde för av detta projekt. Servern lyssnar efter klientförfrågningar på denna port.
Metoden IdTCPServer1Execute är associerad med serverns OnExecute-händelse. OnExecute-händelsen uppstår efter att klientanslutningen har accepterats. OnExecute-händelsen skiljer sig från andra händelser du känner till. OnExecute körs i kontexten av en tråd. Trådhändelsen höjs och ges AThread-argumentet som skickas till metoden. Detta är viktigt eftersom flera OnExecute-händelser kan köras samtidigt. Detta görs för att servern ska kunna fungera utan att skapa en ny komponent. Det finns även metoder som kan åsidosättas vid konstruktion av arvingar.
OnConnect-händelsen aktiveras efter att anslutningen har accepterats och en tråd har skapats för den. I denna server används detta för att skicka ett välkomstmeddelande till klienten. Om så önskas kan detta även göras i OnExecute-händelsen.
OnExecute-händelsen kan avfyras flera gånger tills anslutningen kopplas bort eller förloras. Detta eliminerar behovet av att kontrollera anslutningen för frånkoppling eller förlust i en slinga inom en händelse.
IdTCPServer1Execute använder två grundläggande funktioner, ReadLn och WriteLn. ReadLn läser en sträng från anslutningen och WriteLn skickar en sträng till anslutningen.
sCommand:= ReadLn;
Ovanstående kod tar en sträng från klienten och placerar den i den lokala sCommand-strängvariabeln.

om SameText (sCommand, "QUIT" ) börja sedan

slut annars om SameText (Kopiera (sCommand, 1 , 8 ), "Postkod " ) och börja sedan

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

slutet ;


Därefter kontrolleras sCommand för giltiga kommandon.
Om kommandot är "Avsluta" utförs frånkoppling. Ingen läsning eller skrivning är tillåten efter frånkoppling. Efter att händelsen avslutats anropar den inte längre avlyssningstråden, utan rensar tråden och avslutar anslutningen.
Om kommandot är "ZipCode", så extraheras parametern efter kommandot och tabellen skannas för närvaron av staden och staten. Staden och staten skickas sedan till klienten, eller så skickas en tom sträng om det inte finns någon matchning.
Därefter avslutas metoden. Servern kommer att upprepa händelseanropet igen så snart det anländer nytt lag, vilket gör att klienten kan skicka flera kommandon.
Klientens källkod

enhet ClientMain;

gränssnitt

använder

Windows, meddelanden, SysUtils, klasser, grafik, kontroller, formulär, dialogrutor,

StdCtrls, ExtCtrls, IdAntiFreezeBase,

IdAntiFreeze, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient;

typ

TformMain = klass(TForm)

Klient: TIDTCPClient;

IdAntiFreeze1: TIdAntiFreeze;

Panel1: TPanel;

Panel2: TPanel;

MemoInput: TMemo;

LboxResults: TListBox;

Panel3: TPanel;

Knapp1: TBnapp;

Knapp 2: TB-knapp;

Etikett1: TLabel;

procedure Button2Click(Sender: TObject );

procedure Button1Click(Sender: TObject );

privat

offentlig

slutet ;

FormMain: TformMain;

genomförande

(R*.DFM)

procedure TformMain.Button2Click (Avsändare: TObject );

Börja

MemoInput.Clear ;

LboxResults.Clear ;

slutet ;

procedure TformMain.Button1Click (Avsändare: TObject );

I: heltal ;

S: sträng ;

Börja

ButnLookup.Enabled := true ; Prova

LboxResults.Clear ;

med klienten börjar

Ansluta; Prova

LboxResults.Items.Add(ReadLn);

för i:= 0 till memoInput.Lines .Count - 1 börjar

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

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

S:= ReadLn ;

om s = "" börja då

S:= "-- Ingen post hittades för detta postnummer.";

slutet ;

LboxResults.Items.Add(s);

LboxResults.Items.Add("");

slutet ;

WriteLn("Avsluta");

slutligen Koppla bort; slutet ;

slutet ;

slutligen butnLookup.Enabled := true ; slutet ;

slutet ;

slutet.


De enda delarna som är specifika för klientkomponenten är Button1Click-metoden.
Klientkomponenten är av typen TIdTCPClient och placeras på formuläret. Följande egenskaper har ändrats: ·Host = 127.0.0.1 - Servern finns på samma maskin som klienten. ·Port = 6000 - Serverport
Button1Click-metoden är associerad med OnClick-händelsen för Button1-komponenten. När knappen klickas anropas denna metod. Indy-delen av denna metod kan reduceras till följande: 1.Anslut till servern (Anslut;) 1.Läs hälsningen från servern. 1. För varje rad som angetts av användaren i TMemo: 1. Skicka en begäran till servern (WriteLn("Postkod " + memoInput.Lines[i]);) 1. Läsa ett svar från servern (s:= ReadLn; ) 1. Skickar kommandot Quit (WriteLn("Avsluta");) 1.Koppla bort (Koppla bort;)
Testning
Det här exemplet har testats och fungerar med TCP/IP installerat. Du kan ändra den så att den fungerar över ett nätverk från en dator till en annan. Genom att starta servern på en annan dator och ändra namn eller IP på servern på klienten.
För att testa projekt, kompilera och kör servern. Kompilera och kör sedan klienten. Ange ditt postnummer i memofältet och tryck på uppslagstangenten.
Felsökning
Textprotokoll är mycket lätta att felsöka eftersom de kan testas med Telnet. För att göra detta räcker det att känna till serverporten. ZIP Code Lookup Server lyssnar på port 6000.
Starta ZIP Code Lookup Server igen. Öppna sedan en konsol (t.ex. ett Dos-fönster). Ange nu:
telnet 127.0.0.1 6000
Du är nu ansluten till servern. Vissa servrar skickar också ett välkomstmeddelande. Vissa gör det inte. Du kommer inte att se raderna du anger. De flesta servrar ekar inte för att spara trafik. Du kan dock ändra telnet-inställningarna genom att ställa in alternativet "Echo On". Detta görs olika i olika telnet-klienter, och vissa har inte den här funktionen alls. Ange nu:
postnummer 37642
Du kommer att se serverns svar:
CHURCH HILL, TN
För att koppla från servern anger du:
sluta
Exempel 2 - databasåtkomst
Det här exemplet emulerar en server som måste utföra andra blockeringsuppgifter än socket-anrop. Många servrar tvingas arbeta under sådana förhållanden. Servrar som behöver komma åt databasen, anropa externa procedurer eller beräkningar kan ofta inte avbryta dessa samtal, eftersom de är externa samtal eller på grund av komplexiteten i detta. Åtkomst till databasen kan inte delas upp i små bitar och utvecklaren måste vänta på slutet av operationen med databasen. Detta är en funktion inte bara för databasanrop, utan också för andra operationer såsom komprimering, beräkningar och annan bearbetning av samma slag.
För demonstrationsändamål, låt oss föreställa oss att servern gör ett databasanrop som tar 5 sekunder att slutföra. För att förenkla, låt oss göra detta helt enkelt med en paus, använd Sleep(5000)-funktionen för detta, istället för att faktiskt ringa.
Det här exemplet kräver också mindre detaljer än det föregående exemplet eftersom många av begreppen ännu inte är förstått.
Källa

huvudenhet;

gränssnitt

använder

Windows, meddelanden, SysUtils, klasser, grafik, kontroller, formulär, dialogrutor,

IdBaseComponent, IdComponent, IdTCPServer;

typ

TformMain = klass(TForm)

IdTCPServer1: TIdTCPServer;

procedure IdTCPServer1Execute(AThread: TIdPeerThread) ;

privat

offentlig

slutet ;

FormMain: TformMain;

genomförande

(R*.DFM)

procedure TformMain.IdTCPServer1Execute (AThread: TIdPeerThread) ;

I: heltal ;

Börja

med AThread.Connection börjar

WriteLn("Hej. DB-server redo." );

I:= StrToIntDef(ReadLn, 0);

// Sleep ersätter ett långt DB eller annat samtal

Sömn(5000);

WriteLn(IntToStr(i * 7));

slutet ;

slutet ;

slutet.

Eftersom Execute-händelsen inträffar i kontexten av en tråd, kan bearbetningskoden vara av valfri längd. Varje klient har sin egen tråd och blockerar inte andra klienter.
Testning
För att testa DB-servern, kompilera och kör den. Anslut till den med Telnet till port 6001. Servern kommer att svara med ett välkomstmeddelande. Skriv in nummer. Servern kommer att "behandla" din förfrågan och svara inom 5 sekunder.

Hej alla!

Vid utvecklingen av nästa webbprojekt uppstod uppgiften - att implementera klientprogramvara i Delphi, som skulle överföra data till servern med POST-metoden. Applikationen måste överföra text och ladda upp filer till webbservern.

Implementeringen av sådan datasändning med hjälp av webbutvecklingsspråk på serversidan (till exempel PHP) är ganska enkel, men om du behöver skriva applikationsbaserad, fleranvändarprogramvara som interagerar med servern, så är det lite mer komplicerad. Metoden att direkt ansluta till databasen och via FTP till servern från Delphi är inte längre nödvändig eftersom det är inte säkert, inte tillförlitligt (byta lösenord, anslutningsdata, etc.) och skapar ytterligare. ppå klientsidan. För att lösa problemet bestämde jag mig för att skriva skript i PHP (serverdel) som kommer att behandla inkommande POST-förfrågningar och returnera resultatet till klienten (Delphi-applikationen). Fördelarna med detta tillvägagångssätt är att alla anslutningar och databehandling sker på servern, vilket är mycket säkrare än en direkt "anslutning".

När jag började googla lämnades mycket spridd information upp, mest på forum, men allt var i bitar. En sak var säker att Indy skulle användas, nämligen IdHTTP-komponenten med POST-metoden implementerad. I huvudsak är allt enkelt, den här metoden tar två parametrar Url för resursen och DataStream (dataström), och som svar returnerar den resultatet i textform (det kan också vara sidans HTML-kod). Huvudsaken var korrekt formation DataStream (ström av överförd data), men på vägen kom ytterligare fallgropar, nämligen rysk kodning (om den inte vore bra). Det var här det roliga började för flera timmars vandrande runt på Internet. I allmänhet, tillräckligt med prat, låt oss gå vidare till övning och implementering av programvaran.

Så programmet är enkelt. Hon måste skicka data till servern med POST-metoden, data innehåller " Rubrik " (rad), " Beskrivning " (text med flera rader) och grafisk fil(jpg,png,gif-binära data). Servern måste acceptera denna data, bearbeta den, spara grafikfilen på servern och returnera ett svar. Som ett svar kommer vi att returnera Delphi till applikationen, samma text endast med tillagda etiketter och en länk till den nedladdade filen. Inget annat.

Låt oss börja med implementeringen av serverdelen (liknande webbplatsens API). Öppna valfri textredigerare (anteckningsblock) och skriv följande kod i den:

"; ) else ( eko "Titel: Saknas"."
"; ) //Kontrollera inkommande data för närvaron av "innehålls"-fältdata if (!empty($_POST["content"]))( echo "Content: ".$_POST["content"]."
"; ) else ( eko "Innehåll: Saknas"."
"; ) //Kontrollera inkommande data för närvaron av en bifogad fil "fil" om (!empty($_FILES["fil"])) ( $finfo = pathinfo($_FILES["file"]["name" ]); / /få information om filen (namn, filtillägg, etc.) //Kontrollera filtypen i listan över tillåtna typer (IMPROVISATION:)) if (stripos("jpgpnggif",$finfo["extension"] )==0)( echo ">>>>>>>Ogiltig filtyp<<<<<<<<"; exit; //Если не допустим тип, полностью останавливаем скрипт } $fname = "files/" . "testimgfile." . $finfo["extension"]; //формируем путь и новое имя файла move_uploaded_file($_FILES["file"]["tmp_name"],$fname);//сохраняем временный файл "tmp_name" в файл $fname echo "http://".$_SERVER["HTTP_HOST"]."/".$fname; //возвращаем полный путь к файлу } ?>

notera! När du sparar (via anteckningar) måste du ange kodningen "UTF-8", annars kommer det att bli problem med att visa det kyrilliska alfabetet!

Manuset försökte ge detaljerade kommentarer. Kopiera detta skript till din webbserver, om du inte har ett kan du använda mitt skript för testet, det finns på: http://api..php

Layouten använder följande komponenter: Label, Button (2 st.), Edit (2 st.), Memo (2 st.), CheckBox, OpenDialog, IdHTTP. Ge följande komponenter namn (egenskap " namn”):

  1. Redigera (titel) – Namn=titel;
  2. Redigera (sökväg till fil) Namn = imgfile;
  3. Memo (innehåll)Namn = innehåll;
  4. Memo(resultat) – Namn = svar;
  5. Knapp(…) - Namn = chkfile;
  6. Knapp (POST) – Namn = PostBut;
  7. OpenDialog (filvalsdialog) – Namn = PictDialog;

Låt oss lämna IdHTTP1 och CheckBox1 oförändrade (trött! :)))).

För att inte av misstag" redigera» sökväg till Edit( imgfile), ställ in dess ReadOnly-egenskap till True. Likaså kl imgfile Och chkfile Ställ in egenskapen Enabled till false. Vi kommer att aktivera dem med hjälp av CheckBox, dvs. Vi ger dig möjligheten att välja om du vill ladda upp en bild eller inte.

För OpenDialog( PictDialog) måste du ställa in filtret (Filter-egenskap) enligt följande:

Själva visuella förberedelserna är över! Låt oss börja koda!

I projektet kommer vi att generera ett dataflöde med den typ som ingår i Indy - TidMultiPartFormDataStream.Även om vi stötte på implementeringsalternativ med TStream, arbetade med TidMultiPartFormDataStream – lättare!

För att göra denna typ tillgänglig för vårt projekt måste vi lägga till följande bibliotek till Användningar: IdMultipartFormData.

För CheckBox1, skapa en OnClick-händelse (genom att dubbelklicka med musen på ett objekt) och lägg till följande kod till denna händelse:

Procedur TForm1.CheckBox1Click(Avsändare: TObject); börja //aktivera eller inaktiva filsökvägselementen och dialogknapparna imgfile.Enabled:=CheckBox1.Checked; chkfile.Enabled:=CheckBox1.Checked; slutet;

Här aktiverar vi objekten imgfile Ochchkfile beroende på närvaron av en bock (om kryssrutan är markerad blir objekten aktiva).

Låt oss nu organisera bildvalet. För att göra detta, skapa en OnClick-händelse på knappen chkfile(även genom att dubbelklicka på objektet) och skriv följande:

Procedur TForm1.chkfileClick(Avsändare: TObject); börja //öppna dialogrutan och ange hela sökvägen till filen i imgfile(TEdit) om PictDialog.Execute sedan imgfile.Text:= PictDialog.FileName; slutet;

Den här händelsen utlöser en dialogruta för bildval och om användaren klickar på " Öppen", kommer sökvägen till den här filen att läggas till imgfile.

Och nu kommer vi till den sista "POST"-knappen. Skapa en OnClick-händelse för den här knappen och lägg till följande kod:

Procedur TForm1.PostButClick(Avsändare: TObject); var dataPost:TIdMultiPartFormDataStream; begin dataPost:=TIdMultiPartFormDataStream.Create; dataPost.AddFormField("title",title.Text,"utf-8").ContentTransfer:= "8bit"; dataPost.AddFormField("content",content.Text,"utf-8").ContentTransfer:= "8bit"; om CheckBox1.Checked och (trim(imgfile.Text)="") sedan //kontrollerar om filen är vald eller inte börjar ShowMessage("Du måste välja en grafisk fil!"); utgång; slutet; if CheckBox1.Checked then dataPost.AddFile("file",imgfile.Text,""); //lägg till ett fält med filen response.Text:= StringReplace(idHTTP1.Post("http://api..php",dataPost),"
",#13#10,); datapost.Free; end;

Så, i ordning (även om det finns kommentarer):

Datapost – objekt av typ TIdMultiPartFormDataStream. Låter dig skapa en POST-förfrågningsstruktur som består av fält av olika typer.

dataPost . AddFormField (" titel ", titel . Text ," utf -8 "). ContentTransfer := " 8 bit "; – lägger till ett fält med namnet "title" i DataPost, ett värde från "title.Text", ställer in kodningen av den överförda datan till "utf-8" (parametern är valfri, men utan dess explicita indikation, kyrillisk sänds med frågetecken "?") och en mycket viktig metod "Content Transfer". Utan denna metod skickas data till servern " abrakadabra" Observera att fältnamnet ("titel") på sändningssidan måste matcha namnet som anges i skriptet: $_POST["titel"].

Data överförs på samma sätt som fältet "innehåll".

dataPost . Lägg till fil (" fil ", imgfile . Text ,"") – med den här raden skapar vi en ström med data från filen.

Det är allt, data genereras, allt som återstår är att överföra det till skriptet på servern och få ett svar:

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

därför att TMemo förstår inte radbrytningstaggen "
", kommer vi att använda " "-funktionen för att ersätta den med begripliga radbrytningar "#13#10".

När allt är klart, rensa minnet från DataPost-objektet med raden:

datapost.Gratis;

Även om detta i vårt exempel kommer att ske automatiskt i slutet av proceduren, men ändå...

Det faktiska resultatet av programmet på skärmen:

Således kan vi skicka så mycket data eller filer till servern som vi vill, bearbeta dessa data på servern och rapportera tillbaka till applikationen resultatet av skriptet. Det kan till och med bara vara 0 eller 1, vilket signalerar att applikationen ska reagera ytterligare.

Allt. Lycka till allihopa. Jag hoppas att informationen var användbar och att du kommer att kunna använda den.

Du kan ladda ner det färdiga exemplet och skriptet.

Fullständig modulkod:

Unit PostUnit; gränssnittet använder Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection, Id IdHTTP, IdMultipartFormData, Vcl.ExtDlgs; typ TForm1 = klass(TForm) IdHTTP1: TIdHTTP; titel: TEdit; innehåll: TMemo; PostBut: TButton; svar: TMemo; Etikett1: TLabel; Etikett2: TLabel; Etikett3: TLabel; imgfile:TEdit; chkfile: TButton; Etikett4: TLabel; CheckBox1: TCheckBox; PictDialog:TOpenDialog; procedur PostButClick(Avsändare: TObject); procedure chkfileClick(Avsändare: TObject); procedure CheckBox1Click(Avsändare: TObject); privata ( Privata deklarationer ) offentliga ( Offentliga deklarationer ) slut; var Form1: TForm1; implementering ($R *.dfm) procedur TForm1.CheckBox1Click(Avsändare: TObject); börja //aktivera eller inaktiva filsökvägselementen och dialogknapparna imgfile.Enabled:=CheckBox1.Checked; chkfile.Enabled:=CheckBox1.Checked; slutet; procedure TForm1.chkfileClick(Avsändare: TObject); börja //öppna dialogrutan och ange hela sökvägen till filen i imgfile(TEdit) om PictDialog.Execute sedan imgfile.Text:= PictDialog.FileName; slutet; procedur TForm1.PostButClick(Avsändare: TObject); var dataPost:TIdMultiPartFormDataStream; begin dataPost:=TIdMultiPartFormDataStream.Create; dataPost.AddFormField("title",title.Text,"utf-8").ContentTransfer:= "8bit"; dataPost.AddFormField("content",content.Text,"utf-8").ContentTransfer:= "8bit"; om CheckBox1.Checked och (trim(imgfile.Text)="") sedan //kontrollerar om filen är vald eller inte börjar ShowMessage("Du måste välja en grafisk fil!"); utgång; slutet; if CheckBox1.Checked then dataPost.AddFile("file",imgfile.Text,""); //lägg till ett fält med filen response.Text:= StringReplace(idHTTP1.Post("http://api..php",dataPost),"
",#13#10,); datapost.Free; end; end.

Indy är ett ganska kraftfullt paket med komponenter som låter dig utveckla olika nätverksapplikationer. I den här handledningen kommer jag att berätta hur du kan skapa klient-serverapplikationer med hjälp av komponenterna TIdTCPClient och TIdTCPServer.

Först och främst skulle jag vilja notera två viktiga fördelar med dessa komponenter. Den viktigaste av dem är multithreading, vilket innebär att servern skapar en separat tråd för varje klient, och detta påverkar säkert serverprogrammets prestanda på datorer med en flerkärnig processor. Den andra fördelen är användarvänligheten. 10-20 rader kod räcker för att skriva en enkel klient-serverapplikation. Detta paket med komponenter finns i standard Delphi-aggregat.

Låt oss skriva ett enkelt program som låter dig överföra ett textmeddelande från en klient till en server. Låt oss börja skapa servern.
Låt oss placera IdTCPServer-komponenten från fliken "Indy-servrar" i formuläret. Vi kommer att göra alla inställningar för den här komponenten vid körning i OnCreate-händelsen i formuläret:
IdTCPServer1.DefaultPort:= 12345;
IdTCPServer1.Active:= sant;
Allt är enkelt här - vi anger porten som servern kommer att fungera på och aktiverar själva servern.

För att ta emot data på servern från klienten finns det en speciell händelse "OnExecute". Denna händelse ser ut så här:

Börja
slutet;

Låt oss redigera händelseinnehållet enligt följande:
procedure TForm3.IdTCPServer1Execute(AContext: TIdContext);
var
l:sträng; // strängvariabel som vi kommer att ta emot
Börja
l:= AContext.Connection.IOHandler.ReadLn();
Memo1.Lines.Add(l);
slutet;

Nu, så snart ett meddelande kommer till servern, kommer vi att skriva det till strängvariabeln l och mata ut det till ett flerrads textfält.

Detta slutar, inte överraskande, skapandet av servern. Indy gör resten åt oss. Låt oss börja med klientprogrammet. Den kommer att ansluta till servern, skicka ett meddelande till den och koppla från servern.

Låt oss skapa ett nytt projekt och placera IdTCPClient-komponenten på formuläret, som finns på fliken "Indy Clients". Vi kommer också att placera en enkel redigering och en knapp. Låt oss skapa en OnClick-händelsehanterare för knappen, i vilken vi kommer att skriva:
IdTCPClient1.Port:= 12345;
IdTCPClient1.Host:= '127.0.0.1';
IdTCPClient1.Connect;
IdTCPClient1.IOHandler.WriteLn(Edit1.Text);
IdTCPClient1.Disconnect;

Denna kod behöver inte placeras i OnCreate-händelsen. Du kan placera den här koden var du vill om du vill.
På den första raden tilldelar vi en port, och det är nödvändigt att ange samma port som vi angav i serverprogrammet, annars kommer klienten helt enkelt inte att hitta servern. Sedan anger vi serverns IP-adress. Själva servern kan placeras antingen på det lokala nätverket eller på distans. I det senare fallet kommer anslutningen att göras via Internet och du måste ange en IP-adress på Internet.

Jag angav adressen "127.0.0.1", vilket betyder att servern är den dator som klienten körs på. Denna metod är mycket praktisk för att testa nätverksapplikationer.
Sedan gör vi en koppling, skickar ett meddelande och kopplar ur. Precis som själva meddelandet kan du också ta IP-adressen från Edit eller från valfri strängvariabel.

Arbetet med klientprogrammet är också avslutat. Som du kan se gör Indy ett fantastiskt jobb för oss, vilket gör det möjligt för även en oerfaren programmerare att skapa sin egen nätverksapplikation.

Nytt på sajten

>

Mest populär