Verificarea conexiunilor prize în Delphi. Delphi. Prize de programare în Delphi. Trimiterea și primirea de date complexe

Prize (din priză (în engleză) - conector, priză) sunt interfata software, oferind schimb de informații între procese.

Unul dintre principalele avantaje ale schimbului de informații despre socket în rețea este flexibilitatea acestuia. Principiul principal al lucrului cu socket-uri este de a trimite o secvență de octeți către alt computer, acesta poate fi un simplu mesaj text sau un fișier.

Este important să se facă distincția între două tipuri de prize: prize client , Și prize de server .

Pentru a lucra cu prize de tip „client” în Delphi, există o componentă TClientSocket, puteți lucra cu socket-uri „server” folosind componenta TServerSocket.

Instalarea componentelor

Adesea, componentele TServerSocket și TClientSocket nu sunt incluse în pachetul standard de instalare Delphi, dar pot fi instalate suplimentar.

Accesați fila componente „Internet” și verificați dacă componentele TServerSocket și TClientSocket sunt prezente acolo; dacă nu, instalați-le. Accesați meniul „Componente/Instalare pachete”, apoi faceți clic pe butonul „Adăugați”. În caseta de dialog care se deschide, trebuie să găsiți fișierul „dclsocketsXX.bpl” (se află în folderul bin, care se află în folderul Delphi), unde XX este numărul numeric al versiunii Delphi. Găsiți fișierul, faceți clic pe Deschidere, apoi în fereastra Instalare pachete, faceți clic pe OK. Acum, două componente au apărut în fila „Internet” - TServerSocket și TClientSocket.

Lucrul cu prizele client (tClientSocket)

1) Definirea proprietăților Port și Gazdă. Pentru proprietăți de conectare de succes PortȘi Gazdă Componentei TClientSocket trebuie să i se atribuie niște valori. În proprietatea Port, trebuie să specificați numărul portului pentru conectare (1 – 65535, dar este mai bine să îl luați din intervalul 1001 – 65535, deoarece numerele până la 1000 pot fi ocupate de serviciile de sistem).

Gazdă- numele gazdă sau adresa IP a computerului la care doriți să vă conectați. De exemplu, rus.delphi.com sau 192.128.0.0.

2) Deschiderea unei prize. Vom considera un socket ca o coadă de caractere transmise de la un computer la altul. Puteți deschide o priză apelând metoda Deschis(componenta TClientSocket) sau prin atribuirea unei valori Adevărat proprietate Activ. Aici ar fi util să adăugați un handler de excepții în cazul unei conexiuni eșuate.

3) Trimiterea/primirea datelor.

4) Închiderea prizei. La finalizarea schimbului de date, trebuie să închideți soclul apelând metoda Închide componentă TClientSocket sau prin atribuirea unei valori Fals proprietate Activ.

Proprietățile de bază ale componentei TClientSocket

Indică dacă priza este deschisă sau închisă. Deschis – Adevărat, închis – Fals. Disponibil pentru înregistrare.

Nume de gazdă la care să vă conectați

Adresa IP a computerului la care doriți să vă conectați. Spre deosebire de Host, aici poate fi specificat doar IP. Diferența este că, dacă gazda specifică numele alfabetic al computerului, atunci IP-ul va fi solicitat de la DNS

Numărul portului computerului la care să vă conectați (1-65535)

ClientType

Conține tipul de transfer de date:

ctBlocare- transmisie sincrona ( OnReadȘi OnWrite nu funcționează). Tipul de conexiune sincronă este potrivit pentru schimbul de date în flux;

ctNonBlocking- transmisie asincronă (trimiterea/primirea datelor se poate face folosind evenimente OnReadȘi OnWrite)

Metode de bază ale componentei TClientSocket

Deschide un socket (setarea proprietății Active la True)

Închide socket-ul (setarea proprietății Active la False)

Evenimentele principale ale componentei TClientSocket

OnConnect

Apare atunci când se stabilește o conexiune. În handler puteți începe acum autorizarea sau trimiterea/primirea datelor

OnConnecting

Apare și la conectare. Diferă de OnConnect prin faptul că conexiunea nu a fost încă stabilită. Cel mai adesea folosit, de exemplu, pentru a actualiza starea

OnDisconnect

Evenimentul are loc atunci când socket-ul este închis de programul dvs., computerul de la distanță sau din cauza unei defecțiuni

Evenimentul are loc atunci când există o eroare. În timpul deschiderii unui socket, acest eveniment nu va ajuta la detectarea unei erori. Pentru a evita un mesaj de eroare de la Windows, este mai bine să aveți grijă de gestionarea excepțiilor interne, plasând instrucțiuni deschise într-un bloc " incearca..cu exceptia »

OnLookup

Evenimentul are loc atunci când încercați să obțineți o adresă IP de la DNS

Evenimentul are loc atunci când un computer la distanță vă trimite orice date. Când apelați OnRead, este posibil să procesați datele primite

Evenimentul are loc atunci când programului dumneavoastră i se permite să scrie date în socket

Acest articol va discuta proprietățile și funcțiile de bază Componentele Delphi: TClientSocket și TServerSocket – utilizate pentru a lucra cu rețeaua folosind protocolul TCP\IP.

Atenţie! Dacă utilizați o versiune de Delphi mai mare decât 6.0, atunci trebuie mai întâi să instalați Sockets Components; în toate versiunile de Delphi, acest lucru se face după cum urmează:

  • Accesați dialogul Instalare pachete...: (meniul principal) Componentă -> Instalare pachete;
  • Faceți clic pe butonul Adaugă..., după care găsim folderul Bin al Delphi-ului dvs. (de exemplu: C:\Program Files\Borland\Delphi 7\bin, sau C:\Program Files\Embarcadero\RAD Studio\7.0\Bin) ;
  • În folderul Bin găsit, căutăm deja fișierul dclsockets [aici sunt numerele].bpl, faceți clic pe OK;
  • Suntem fericiți pentru că acum avem două componente minunate TServerSocket și TClientSocket în fila Internet a panoului de componente.

Când se dezvoltă orice aplicație de rețea, de obicei, dezvoltarea începe întotdeauna cu serverul (desigur, dacă aveți o echipă, designerii de interfețe pot începe să lucreze la client). Pentru a implementa un server, în mod surprinzător, trebuie să utilizați TServerSocket.

Proprietăți de bază:

  • Activ– un câmp boolean, când este setat la true – serverul pornește, îl puteți folosi fie prin alocarea unor valori specifice, fie apelând funcțiile ServerSocket1.Open (... Active:=true;) sau ServerSocket1.Close (.. .Activ:=fals).
  • Port– portul pe care serverul va asculta (primi clienți), orice valoare din intervalul neocupat de alte servere din sistem întreg.

Evenimente principale:

  • OnListen– apelat când serverul este setat în modul de ascultare, poate fi folosit atunci când trebuie să stabilim ora pornirii reale a serverului.
  • OnClientRead– apelat atunci când datele sunt primite de la client.
  • OnClientError
  • OnClientConnect– Apelat când un nou client se alătură serverului.
  • OnClientDisconnect- inversează eveniment la eveniment, OnClientConnect

fiecare funcție de eveniment are un atribut Socket: TCustomWinSocket, un pointer către obiectul socket în care ne aflăm acest moment lucrăm, dacă trebuie să răspundem sau să facem ceva cu clientul care a provocat evenimentul, trebuie să folosim acest obiect special, în toate celelalte cazuri folosim ServerSocket1.Socket, situația este similară cu componenta client.

Proprietăți și funcții numai pentru citire:

  • – returnează numărul de conexiuni active.
  • ServerSocket1.Socket.Connexions– o matrice de obiecte de tip TCustomWinSocket, o matrice cu toate obiectele asociate cu clienții, numărarea indexului începe de la 0, lungimea matricei este ServerSocket1.Socket.ActiveConnections.
  • Funcții și proprietăți care se aplică elementelor matricei ServerSocket1.Socket.Connections și atributului Socket transmis funcției de eveniment server:
  • Socket.LocalHost
  • Socket.LocalAddress– returnează IP-ul serverului.
  • Socket.RemoteHost
  • Socket.RemoteAddress– returnează IP-ul clientului.
  • Socket.ReceiveText– returnează un mesaj text primit de la client, după care șterge bufferul, poate fi folosit doar 1 dată, la 1 recepție.
  • Socket.SendText(Text)– trimite clientului un mesaj text de tip Text şir.

Pentru componenta TClientSocket totul este practic la fel, doar invers + principala diferență vizuală dintre server și client este că serverul din sistem poate fi lansat 1 cu 1 valoarea portului, numărul de clienți este limitat doar de RAM .

Proprietăți de bază:

  • Activ– un câmp boolean, când este setat la true – clientul încearcă să se conecteze la server, poate fi folosit fie prin alocarea unor valori specifice, fie apelând funcțiile ClientSocket1.Open (... Active:=true;) sau ClientSocket1 .Închidere (... Activ:=fals) .
  • Port– port prin care clientul se poate conecta la server, orice valoare din interval întreg.
  • Abordare– adresa IPv4 a tipului de server şir conform modelului 255.255.255.255, cu care clientul se va conecta.

Evenimente principale:

  • OnRead– apelat când se primesc date din nord.
  • OnError– apelat atunci când apare o eroare în transmiterea datelor.
  • OnConnecting– Apelat când un client se alătură serverului.
  • OnDisconnect- inversează eveniment la eveniment, OnConnecting, apelat când un client se deconectează de la server.

Proprietăți și funcții numai pentru citire:

  • ClientSocket1.Socket.SendText() şir
  • Socket.LocalHost– returnează numele online al clientului.
  • Socket.LocalAddress– returnează IP-ul clientului.
  • Socket.RemoteHost– returnează numele serverului din rețea.
  • Socket.RemoteAddress– returnează IP-ul serverului.
  • Socket.ReceiveText– returnează un mesaj text primit de la server, după care șterge bufferul, putând fi folosit doar 1 dată, la un moment dat.
  • Socket.SendText(Text)– trimite un mesaj text de tip Text către server şir.

Informațiile furnizate sunt destul de suficiente pentru a implementa un mic server de chat care satisface specificatii tehnice: internet_sockets.doc (Word Doc 97-2003, 26,5 Kb).

Acest articol a fost scris duminică, 10 octombrie 2010 la 1:24 am în secțiunea. Vă puteți abona la actualizări privind comentariile la articol -. Puteți


Introducere


Acest articol este dedicat creării de aplicații de arhitectură client/server în Borland Delphi bazate pe socket-uri („socket-uri” - cuiburi). Spre deosebire de articolul anterior pe tema socket-urilor, aici ne vom uita la crearea aplicațiilor server.

Trebuie remarcat imediat că pentru coexistența unor aplicații separate client și server, nu este necesar să aveți mai multe computere. Este suficient să ai doar unul pe care să poți rula simultan atât serverul, cât și clientul. În acest caz, trebuie să utilizați numele gazdei ca nume al computerului la care doriți să vă conectați gazdă locală sau adresa IP - 127.0.0.1 .

Deci, să începem cu teoria. Dacă sunteți un practicant convins (și nu puteți vedea niciun algoritm cu ochii), atunci ar trebui să săriți peste această secțiune.

Algoritm de operare a serverului socket


Ce vă permite să faceți un server socket?.. Pe ce principiu funcționează?.. Un server bazat pe protocolul socket vă permite să deserviți mai mulți clienți simultan. Mai mult, puteți specifica singur limita pentru numărul lor (sau eliminați această limită cu totul, așa cum se face în mod implicit). Pentru fiecare client conectat, serverul deschide o priză separată prin care puteți face schimb de date cu clientul. O altă soluție excelentă este crearea unui proces separat (Thread) pentru fiecare conexiune.

Mai jos este un exemplu de diagramă a modului în care funcționează un server socket în aplicațiile Delphi:

Să ne uităm la diagramă mai detaliat:

  • Definiția proprietăților Port și ServerType - pentru ca clientii sa se poata conecta la server in mod normal, este necesar ca portul folosit de server sa se potriveasca exact cu portul folosit de client (si invers). Proprietatea ServerType determină tipul de conexiune (vezi mai jos pentru mai multe detalii);
  • Deschiderea unei prize - deschiderea prizei si a portului specificat. Aici începem automat să așteptăm ca clienții să se conecteze ( Asculta);
  • Conectarea unui client și schimbul de date cu acesta - aici clientul se conectează și schimbă date cu acesta. Mai multe despre această etapă puteți afla mai jos în acest articol și în articolul despre socket-uri (partea client);
  • Dezactivarea unui client - Aici clientul se deconectează și conexiunea lui socket cu serverul este închisă;
  • Închiderea serverului și a prizei - La comanda administratorului, serverul se oprește, închizând toate canalele socket deschise și oprind așteptarea conexiunilor clientului.

Trebuie remarcat faptul că punctele 3-4 se repetă de mai multe ori, adică. Acești pași sunt efectuati pentru fiecare nouă conexiune client.

Notă : Există foarte puțină documentație despre socket-uri în Delphi în acest moment, așa că dacă doriți să studiați acest subiect cât mai profund posibil, vă sfătuiesc să vă uitați prin literatura și documentația electronică despre sistemele Unix/Linux - acolo Foarte Teoria lucrului cu prize este bine descrisă. În plus, există multe exemple de aplicații socket pentru aceste sisteme de operare (deși mai ales în C/C++ și Perl).

Scurtă descriere a componentei TServerSocket


Aici ne vom familiariza principal proprietățile, metodele și evenimentele unei componente TServerSocket.

Proprietăți

Priză - clasa TServerWinSocket, prin care aveți acces la canalele socket deschise. În continuare vom lua în considerare această proprietate mai detaliat, deoarece este, de fapt, una dintre cele principale. Tip: TServerWinSocket ;
ServerType - tipul serverului. Poate lua una dintre cele două valori: stNonBlocking- lucru sincron cu prizele client. Cu acest tip de server poți lucra cu clienții prin evenimente OnClientReadȘi OnClientWrite. stThreadBlocking- tip asincron. Un proces separat (Thread) este creat pentru fiecare canal de socket client. Tip: TServerType ;
ThreadCacheSize - numărul de procese client (Thread) care vor fi stocate în cache de către server. Aici trebuie să selectați valoarea medie în funcție de încărcarea serverului dvs. Memorarea în cache are loc pentru a nu crea de fiecare dată un proces separat și pentru a nu ucide un socket închis, ci pentru a le lăsa pentru utilizare ulterioară. Tip: Întreg ;
Activ - un indicator dacă serverul este activ la un moment dat sau nu. Aceasta este, de fapt, valoarea Adevărat indică faptul că serverul rulează și gata să primească clienți și Fals- serverul este oprit. Pentru a porni serverul, trebuie pur și simplu să setați această proprietate la Adevărat. Tip: boolean ;
Port - numarul portului pentru stabilirea conexiunilor cu clientii. Porturile server și client trebuie să fie aceleași. Sunt recomandate valori de la 1025 la 65535, deoarece de la 1 la 1024 - poate fi ocupat de sistem. Tip: Întreg ;
Serviciu - un șir care definește serviciul ( ftp, http, pop, etc.) al cărui port va fi utilizat. Acesta este un fel de director de numere de porturi care corespund diferitelor protocoale standard. Tip: şir ;

Deschis - Pornește serverul. În esență, această comandă este identică cu alocarea unei valori Adevărat proprietate Activ;
Închide - Oprește serverul. În esență, această comandă este identică cu alocarea unei valori Fals proprietate Activ.

OnClientConnect - apare atunci când clientul a stabilit o conexiune socket și așteaptă un răspuns de la server ( OnAccept);
OnClientDisconnect - Apare atunci când clientul s-a deconectat de la canalul de socket;
OnClientError - apare atunci când operațiunea curentă eșuează, adică A avut loc o eroare;
OnClientRead - apare atunci când clientul a trimis unele date către server. Aceste date pot fi accesate printr-un parametru transmis Socket: TCustomWinSocket;
OnClientWrite - apare atunci când serverul poate trimite date către client printr-un socket;
OnGetSocket - în handlerul acestui eveniment puteți edita parametrul ClientSocket;
OnGetThread - în handlerul acestui eveniment puteți defini un proces unic (Thread) pentru fiecare canal individual de client prin alocarea parametrului SocketThread subsarcina dorită TServerClientThread;
OnThreadStart , OnThreadEnd - apare atunci când o subsarcină (proces, Thread) este pornită sau, respectiv, oprită;
OnAccept - apare atunci când serverul acceptă clientul sau îi refuză o conexiune;
OnListen - apare atunci când serverul intră în modul de așteptare pentru conectarea clienților.


TServerSocket.Socket(TSServerWinSocket)


Deci, cum poate serverul să trimită date către client? Ce zici de primirea datelor? În principal, dacă lucrați prin evenimente OnClientReadȘi OnClientWrite, apoi puteți comunica cu clientul prin parametrul ClientSocket (TCustomWinSocket). Puteți citi despre lucrul cu această clasă în articolul despre socket-urile client, deoarece trimiterea/trimiterea datelor prin această clasă este similară - metode (Send/Receive)(Text,Buffer,Stream). Același lucru este valabil și atunci când lucrați cu TServerSocket.Socket. Cu toate acestea, pentru că Aici luăm în considerare un server, ar trebui să evidențiem câteva proprietăți și metode utile:

  • ActiveConnexions (Întreg) - numărul de clienți conectați;
  • ActiveThreads (Întreg) - numărul de procese în derulare;
  • Conexiuni (matrice) - o matrice formată din clase TClientWinSocket separate pentru fiecare client conectat. De exemplu, această comandă:
    ServerSocket1.Socket.Connections.SendText("Bună ziua!");
    trimite un mesaj „Bună ziua!” primului client conectat. Comenzi pentru lucrul cu elemente din această matrice - de asemenea (Trimite/Primește) (Text, Buffer, Stream);
  • IdleThreads (Întreg) - numărul de procese libere. Astfel de procese sunt stocate în cache de către server (vezi ThreadCacheSize);
  • Adresă locală, Gazdă locală, Local Port- respectiv - adresa IP locală, nume de gazdă, port;
  • RemoteAddress, Gazda la distanta, RemotePort- respectiv - adresa IP la distanță, numele gazdei, portul;
  • Metode LacătȘi Deblocați- respectiv blocarea si deblocarea prizei.

Practică și exemple


Acum să ne uităm la cele de mai sus exemplu concret. Puteți descărca surse gata făcute făcând clic.

Deci, să ne uităm la un exemplu foarte bun de lucru cu TServerSocket (acest exemplu este cel mai bun ajutor vizual pentru studierea acestei componente). Sursele de mai jos demonstrează înregistrarea în jurnal a tuturor evenimentelor importante de server, plus capacitatea de a primi și trimite mesaje text:

Exemplul 1.Înregistrare și studiu operarea serverului, trimiterea/primirea mesajelor prin prize

(...Aici merge antetul fișierului și definiția formei TForm1 și a instanței sale Form1)
(Vezi sursa completă)
procedura TForm1.Button1Click(Expeditor: TObject); ÎNCEPE (Determinați portul și porniți serverul) ServerSocket1.Port:= 1025; (Metoda Insert inserează un șir în matrice la poziția specificată) Memo2.Lines.Insert(0,"Server pornește"); ServerSocket1.Open; Sfârşit; procedura TForm1.Button2Click(Expeditor: TObject); ÎNCEPE (Opriți serverul) ServerSocket1.Active:= False; Memo2.Lines.Insert(0,"Server oprit"); Sfârşit; procedura TForm1.ServerSocket1Listen(Expeditor: TObject; Socket: TCustomWinSocket); ÎNCEPE (Aici serverul „ascultă” pe soclu pentru clienți) Memo2.Lines.Insert(0,"Ascultare pe portul"+IntToStr(ServerSocket1.Port)); Sfârşit; procedura TForm1.ServerSocket1Accept(Expeditor: TObject; Socket: TCustomWinSocket); ÎNCEPE (Aici serverul acceptă clientul) Memo2.Lines.Insert(0,"Conexiune client acceptată"); Sfârşit; procedura TForm1.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket); ÎNCEPE (Aici clientul se conectează) Memo2.Lines.Insert(0,"Client conectat"); Sfârşit; procedura TForm1.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); ÎNCEPE (Aici clientul se deconectează) Memo2.Lines.Insert(0,"Client deconectat"); Sfârşit; procedura TForm1.ServerSocket1ClientError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); ÎNCEPE (A apărut o eroare - afișați codul) Memo2.Lines.Insert(0,"Client error. Code = "+IntToStr(ErrorCode)); Sfârşit; procedura TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); ÎNCEPE (A fost primit un mesaj de la client - afișați-l în Memo1) Memo2.Lines.Insert(0,"Mesaj primit de la client"); Memo1.Lines.Insert(0,"> "+Socket.ReceiveText); Sfârşit; procedura TForm1.ServerSocket1ClientWrite(Sender: TObject; Socket: TCustomWinSocket); ÎNCEPE (Acum puteți trimite date la socket) Memo2.Lines.Insert(0,"Acum pot scrie pe socket"); Sfârşit; procedura TForm1.ServerSocket1GetSocket(Sender: TObject; Socket: Integer; var ClientSocket: TServerClientWinSocket); începe Memo2.Lines.Insert(0,"Obțineți socket"); Sfârşit; procedura TForm1.ServerSocket1GetThread(Sender: TObject; ClientSocket: TServerClientWinSocket; var SocketThread: TServerClientThread); începe Memo2.Lines.Insert(0,"Get Thread"); Sfârşit; procedura TForm1.ServerSocket1ThreadEnd(Sender: TObject; Thread: TServerClientThread); start Memo2.Lines.Insert(0,"Sfârșitul firului"); Sfârşit; procedura TForm1.ServerSocket1ThreadStart(Sender: TObject; Thread: TServerClientThread); start Memo2.Lines.Insert(0,"Început fir"); Sfârşit; procedura TForm1.Button3Click(Expeditor: TObject); var i: întreg; ÎNCEPE (Trimiteți un mesaj către TOȚI clienții de la Edit1) pentru i:= 0 la ServerSocket1.Socket.ActiveConnections-1 nu începe ServerSocket1.Socket.Connections[i].SendText(Edit1.Text); Sfârşit; Memo1.Lines.Insert(0,"

Tehnici de lucru cu TServerSocket (și pur și simplu cu socket-uri)


Stocarea datelor unice pentru fiecare client.


Cu siguranță, dacă serverul dvs. va deservi mulți clienți, atunci va trebui să stocați câteva informații pentru fiecare client (nume etc.) și să legați aceste informații la socket-ul acestui client. În unele cazuri, a face toate acestea manual (legarea la un mâner de socket, matrice de client etc.) nu este foarte convenabilă. Prin urmare, pentru fiecare priză există o proprietate specială - Date. De fapt, Datele sunt doar un indicator. Prin urmare, atunci când scrieți date client în această proprietate, aveți grijă și urmați regulile de lucru cu pointeri (alocarea memoriei, definirea tipului etc.)!

Trimiterea fișierelor prin socket.


Aici ne vom uita la trimiterea fișierelor printr-un socket (la cererea lui JINX) :-). Deci, cum trimiți un fișier printr-un socket? Foarte simplu! Tot ce trebuie să faceți este să deschideți acest fișier ca flux de fișiere (TFileStream) și să-l trimiteți printr-un socket (SendStream)! Să ne uităm la asta cu un exemplu:

Trebuie remarcat faptul că metoda SendStream folosit nu numai de server, ci și de client ( ClientSocket1.Socket.SendStream(srcfile))

De ce pot fi combinate mai multe blocuri într-unul singur în timpul transmisiei?


Asta si la cererea lui JINX :-). Ii multumesc mult pentru asta! Deci, în primul rând, trebuie remarcat faptul că datele trimise printr-un socket nu pot fi combinate doar într-un singur bloc, ci și separate pe mai multe blocuri. Faptul este că un socket este un flux obișnuit, dar spre deosebire, de exemplu, de un flux de fișiere (TFileStream), transferă date mai lent (înțelegeți - rețea, trafic limitat etc.). De aceea două comenzi:
ServerSocket1.Socket.Connections.SendText("Bună ziua, ");
ServerSocket1.Socket.Connections.SendText("lumea!");
complet identic cu o singură comandă:
ServerSocket1.Socket.Connections.SendText("Bună, lume!");

Și de aceea, dacă trimiteți un fișier de, să zicem, 100 KB printr-un socket, atunci persoana căreia i-ați trimis acest bloc va primi mai multe blocuri cu dimensiuni care depind de trafic și aglomerația liniei. Mai mult, dimensiunile nu vor fi neapărat aceleași. Rezultă că pentru a accepta un fișier sau orice alte date marime mare Ar trebui să acceptați blocuri de date și apoi să le combinați într-un singur întreg (și să le salvați într-un fișier, de exemplu). O soluție excelentă la această problemă este același flux de fișiere - TFileStream (sau un flux în memorie - TMemoryStream). Puteți primi date de la un socket prin evenimentul OnRead (OnClientRead) folosind metoda universală ReceiveBuf. Puteți determina dimensiunea blocului rezultat folosind metoda ReceiveLength. De asemenea, puteți utiliza un flux de socket (consultați articolul despre TClientSocket). Și iată un mic exemplu (aproximativ):

Cum să monitorizezi o priză


Această problemă este complexă și necesită o analiză îndelungată. Deocamdată, voi observa doar că puteți monitoriza oricând socket-ul creat de programul dvs. :-). Socket-urile (ca majoritatea obiectelor din Windows) au propriul mâner, scris în proprietatea Handle. Deci, odată ce recunoașteți acest descriptor, veți putea gestiona liber orice socket (chiar și unul creat de programul altcuiva)! Cu toate acestea, cel mai probabil, pentru a monitoriza socket-ul altcuiva, va trebui să utilizați exclusiv funcțiile WinAPI Sockets.


Acest articol arată tehnicile de bază pentru lucrul cu componenta TServerSocket în Delphi și câteva tehnici generale pentru schimbul de date peste socketuri. Dacă aveți întrebări, trimiteți-mi-le pe e-mail: [email protected], și chiar mai bine - scrieți în conferința acestui site (Delphi. Întrebări generale) pentru ca alți utilizatori să vă vadă întrebarea și să încerce să vă răspundă!

Karikh Nikolay ( Nitro). Regiunea Moscovei, Jukovski

Acest articol este dedicat creării de aplicații de arhitectură client/server în Borland Delphi bazate pe socket-uri („sockets”). Spre deosebire de articolul anterior pe tema socket-urilor, aici ne vom uita la crearea aplicațiilor server.
Trebuie remarcat imediat că pentru coexistența unor aplicații separate client și server, nu este necesar să aveți mai multe computere. Este suficient să ai doar unul pe care să poți rula simultan atât serverul, cât și clientul. În acest caz, trebuie să utilizați numele de gazdă localhost sau adresa IP - 127.0.0.1 ca nume al computerului la care trebuie să vă conectați.
Deci, să începem cu teoria. Dacă sunteți un practicant convins (și nu puteți vedea niciun algoritm cu ochii), atunci ar trebui să săriți peste această secțiune.
Algoritm de operare a serverului socket
Ce vă permite să faceți un server socket?.. Pe ce principiu funcționează?.. Un server bazat pe protocolul socket vă permite să deserviți mai mulți clienți simultan. Mai mult, puteți specifica singur limita pentru numărul lor (sau eliminați această limită cu totul, așa cum se face în mod implicit). Pentru fiecare client conectat, serverul deschide o priză separată prin care puteți face schimb de date cu clientul. O altă soluție excelentă este crearea unui proces separat (Thread) pentru fiecare conexiune.
Mai jos este un exemplu de diagramă a modului în care funcționează un server socket în aplicațiile Delphi:

Să ne uităm la schema mai detaliat: · Definiția portului și ServerType - pentru ca clienții să se poată conecta la server în mod normal, este necesar ca portul folosit de server să se potrivească exact cu portul folosit de client (și viceversa). Proprietatea ServerType determină tipul de conexiune (vezi mai jos pentru mai multe detalii); ·Deschiderea unei prize - deschiderea unei prize și a portului specificat. Aici începe automat așteptarea clienților să se conecteze (Ascultă); ·Conectarea unui client și schimbul de date cu acesta - aici clientul se conectează și schimbă date cu acesta. Mai multe despre această etapă puteți afla mai jos în acest articol și în articolul despre socket-uri (partea client); ·Deconectare client - Aici clientul este deconectat și conexiunea lui socket cu serverul este închisă; · Închiderea serverului și a socket-ului - La comanda administratorului, serverul se oprește, închide toate canalele socket deschise și nu mai aștepta conexiunile clientului.
Trebuie remarcat faptul că punctele 3-4 se repetă de mai multe ori, adică. Acești pași sunt efectuati pentru fiecare nouă conexiune client.
Notă: Există foarte puțină documentație despre socket-uri în Delphi în acest moment, așa că dacă doriți să studiați acest subiect cât mai profund posibil, vă sfătuiesc să vă uitați prin literatura și documentația electronică despre sistemele Unix/Linux - teoria lucrului cu prize este foarte bine descris acolo. În plus, există multe exemple de aplicații socket pentru aceste sisteme de operare (deși mai ales în C/C++ și Perl).
Scurtă descriere a componentei TServerSocket
Aici ne vom familiariza cu principalele proprietăți, metode și evenimente ale componentei
Proprietăți
Socket este clasa TServerWinSocket prin care aveți acces la canalele socket deschise. În continuare vom lua în considerare această proprietate mai detaliat, deoarece este, de fapt, una dintre cele principale. Tip: TServerWinSocket;
ServerType - tip de server. Poate lua una dintre cele două valori: stNonBlocking - lucru sincron cu socket-urile client. Cu acest tip de server, puteți lucra cu clienții prin evenimentele OnClientRead și OnClientWrite. stThreadBlocking este un tip asincron. Un proces separat (Thread) este creat pentru fiecare canal de socket client. Tip: TServerType;
ThreadCacheSize - numărul de procese client (Thread) care vor fi stocate în cache de către server. Aici trebuie să selectați valoarea medie în funcție de încărcarea serverului dvs. Memorarea în cache are loc pentru a nu crea de fiecare dată un proces separat și pentru a nu ucide un socket închis, ci pentru a le lăsa pentru utilizare ulterioară. Tip: Integer;
Activ - un indicator care indică dacă serverul este activ sau nu în prezent. Adică, de fapt, valoarea True indică faptul că serverul rulează și este gata să primească clienți, iar False indică faptul că serverul este oprit. Pentru a porni serverul, trebuie pur și simplu să setați această proprietate la True. Tip: boolean;
Port - număr de port pentru stabilirea conexiunilor cu clienții. Porturile server și client trebuie să fie aceleași. Sunt recomandate valori de la 1025 la 65535, deoarece de la 1 la 1024 - poate fi ocupat de sistem. Tip: Integer;
Service - un șir care definește serviciul (ftp, http, pop, etc.) al cărui port va fi utilizat. Acesta este un fel de director de numere de porturi care corespund diferitelor protocoale standard. Tip: sfoară;
Metode
Deschidere - Pornește serverul. În esență, această comandă este identică cu setarea proprietății Active la True;
Închidere - Oprește serverul. În esență, această comandă este identică cu setarea proprietății Active la False.
Evenimente
OnClientConnect - apare atunci când clientul a stabilit o conexiune socket și așteaptă un răspuns de la server (OnAccept);
OnClientDisconnect - apare atunci când clientul s-a deconectat de la canalul socket;
OnClientError - apare atunci când operațiunea curentă eșuează, de exemplu. A avut loc o eroare;
OnClientRead - apare atunci când clientul a transmis anumite date către server. Aceste date pot fi accesate prin intermediul parametrului Socket furnizat: TCustomWinSocket;
OnClientWrite - apare atunci când serverul poate trimite date către client prin socket;
OnGetSocket - în handlerul acestui eveniment puteți edita parametrul ClientSocket;
OnGetThread - în handlerul acestui eveniment puteți defini un proces unic (Thread) pentru fiecare canal individual de client prin alocarea parametrului SocketThread subsarcinii dorite TServerClientThread;
OnThreadStart, OnThreadEnd - apare atunci când o subsarcină (proces, Thread) este pornită sau, respectiv, oprită;
OnAccept - apare atunci când serverul acceptă clientul sau îi refuză o conexiune;
OnListen - apare atunci când serverul intră în modul de așteptare pentru conectarea clienților.
TServerSocket.Socket(TSServerWinSocket)
Deci, cum poate serverul să trimită date către client? Ce zici de primirea datelor? Practic, dacă lucrați prin evenimentele OnClientRead și OnClientWrite, atunci puteți comunica cu clientul prin parametrul ClientSocket (TCustomWinSocket). Puteți citi despre lucrul cu această clasă în articolul despre socket-urile client, deoarece trimiterea/trimiterea datelor prin această clasă este similară - metode (Send/Receive)(Text,Buffer,Stream). Același lucru este valabil și atunci când lucrați cu TServerSocket.Socket. Cu toate acestea, pentru că aici avem în vedere un server, ar trebui să evidențiem câteva proprietăți și metode utile: ·ActiveConnections (Integer) - numărul de clienți conectați; ·ActiveThreads (Integer) - numărul de procese care rulează; ·Conexiuni (matrice) - o matrice formată din clase separate TClientWinSocket pentru fiecare client conectat. De exemplu, această comandă: · ServerSocket1.Socket.Connections.SendText(„Bună ziua!”); · trimite un mesaj „Bună ziua!” primului client conectat. Comenzi pentru lucrul cu elemente din această matrice - de asemenea (Trimite/Primește) (Text, Buffer, Stream); ·IdleThreads (Integer) - numărul de procese gratuite. Astfel de procese sunt stocate în cache de către server (vezi ThreadCacheSize); ·LocalAddress, LocalHost, LocalPort - respectiv - adresa IP locală, numele gazdei, portul; ·RemoteAddress, RemoteHost, RemotePort - respectiv - adresa IP la distanta, numele gazdei, port; ·Metode Blocare și Deblocare - respectiv blocarea și deblocarea prizei.
Practică și exemple
Acum să ne uităm la cele de mai sus folosind un exemplu specific. Puteți descărca surse gata făcute făcând clic aici.
Deci, să ne uităm la un exemplu foarte bun de lucru cu TServerSocket (acest exemplu este cel mai bun ajutor vizual pentru studierea acestei componente). Sursele de mai jos demonstrează înregistrarea în jurnal a tuturor evenimentelor importante de server, plus capacitatea de a primi și trimite mesaje text:
Exemplul 1. Înregistrarea și studierea funcționării serverului, trimiterea/primirea mesajelor prin socket-uri.

(...Aici merge antetul fișierului și definiția formei TForm1 și a instanței sale Form1)

(Vezi sursa completă aici)

procedura TForm1.Button1Click (Expeditor: TObject) ;

ÎNCEPE

(Determinați portul și porniți serverul)

ServerSocket1.Port := 1025 ;

(Metoda Insert inserează un șir în matrice la poziția specificată)

Memo2.Lines .Insert (0 , "Server pornire" );

ServerSocket1.Open ;

Sfârşit ;

procedura TForm1.Button2Click (Expeditor: TObject) ;

ÎNCEPE

(Opriți serverul)

ServerSocket1.Active := False ;

Memo2.Lines .Insert (0 , „Server oprit” );

Sfârşit ;

procedura TForm1.ServerSocket1Listen (Expeditor: TObject ;

Socket: TCustomWinSocket);

ÎNCEPE

(Aici serverul „ascultă” pe soclu pentru clienți)

Memo2.Lines .Insert (0 , "Listening on port" +IntToStr (ServerSocket1.Port) ) ;

Sfârşit ;

procedura TForm1.ServerSocket1Accept (Expeditor: TObject ;

Socket: TCustomWinSocket);

ÎNCEPE

(Aici serverul acceptă clientul)

Memo2.Lines .Insert (0 , "Conexiune client acceptată" );

Sfârşit ;

procedura TForm1.ServerSocket1ClientConnect (Expeditor: TObject ;

Socket: TCustomWinSocket);

ÎNCEPE

(Aici clientul se conectează)

Memo2.Lines .Insert (0 , „Client conectat” );

Sfârşit ;

procedura TForm1.ServerSocket1ClientDisconnect (Expeditor: TObject ;

Socket: TCustomWinSocket);

ÎNCEPE

(Aici clientul se deconectează)

Memo2.Lines.Insert(0,"Client deconectat");

Sfârşit ;

procedura TForm1.ServerSocket1ClientError (Expeditor: TObject ;

Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;

var ErrorCode: Integer);

ÎNCEPE

(A apărut o eroare - afișați codul)

Memo2.Lines.Insert (0,"Client error. Code = " +IntToStr (ErrorCode) ) ;

Sfârşit ;

procedura TForm1.ServerSocket1ClientRead (Expeditor: TObject ;

Socket: TCustomWinSocket);

ÎNCEPE

(A fost primit un mesaj de la client - afișați-l în Memo1)

Memo2.Lines.Insert(0, „Mesaj primit de la client”) ;

Memo1.Lines.Insert(0,">" +Socket.ReceiveText);

Sfârşit ;

procedura TForm1.ServerSocket1ClientWrite (Expeditor: TObject ;

Socket: TCustomWinSocket);

ÎNCEPE

(Acum puteți trimite date la socket)

Memo2.Lines .Insert (0 , "Acum pot scrie pe socket" );

Sfârşit ;

procedura TForm1.ServerSocket1GetSocket (Expeditor: TObject ; Socket: Integer ;

var ClientSocket: TServerClientWinSocket);

ÎNCEPE

Memo2.Lines .Insert (0 , „Obțineți socket” );

Sfârşit ;

procedura TForm1.ServerSocket1GetThread (Expeditor: TObject ;

ClientSocket: TServerClientWinSocket;

var SocketThread: TServerClientThread);

ÎNCEPE

Memo2.Lines.Insert(0,"Get Thread");

Sfârşit ;

procedura TForm1.ServerSocket1ThreadEnd (Expeditor: TObject ;

ÎNCEPE

Memo2.Lines .Insert (0 , „Sfârșitul firului” );

Sfârşit ;

procedura TForm1.ServerSocket1ThreadStart (Expeditor: TObject ;

Thread: TServerClientThread);

ÎNCEPE

Memo2.Lines .Insert (0 , "Început fir" );

Sfârşit ;

procedura TForm1.Button3Click (Expeditor: TObject) ;

var i: Integer ;

ÎNCEPE

(Trimiteți un mesaj către TOȚI clienții de la Edit1)

pentru i:= 0 la ServerSocket1.Socket .ActiveConnections -1 începe

ServerSocket1.Socket.Connections[i].SendText(Edit1.Text);

Sfârşit ;

Memo1.Lines.Insert(0,"< " +Edit1.Text ) ;

Sfârşit ;

În continuare, vom lua în considerare nu exemple, ci metode de lucru cu TServerSocket.
Tehnici de lucru cu TServerSocket (și pur și simplu cu socket-uri)
Stocarea datelor unice pentru fiecare client.
Cu siguranță, dacă serverul dvs. va deservi mulți clienți, atunci va trebui să stocați câteva informații pentru fiecare client (nume etc.) și să legați aceste informații la socket-ul acestui client. În unele cazuri, a face toate acestea manual (legarea la un mâner de socket, matrice de client etc.) nu este foarte convenabilă. Prin urmare, pentru fiecare priză există o proprietate specială - Date. De fapt, Datele sunt doar un indicator. Prin urmare, atunci când scrieți date client în această proprietate, aveți grijă și urmați regulile de lucru cu pointeri (alocarea memoriei, definirea tipului etc.)!
Trimiterea fișierelor prin socket.
Aici ne vom uita la trimiterea fișierelor printr-un socket (la cererea lui JINX) :-). Deci, cum trimiți un fișier printr-un socket? Foarte simplu! Tot ce trebuie să faceți este să deschideți acest fișier ca flux de fișiere (TFileStream) și să-l trimiteți printr-un socket (SendStream)! Să ne uităm la asta cu un exemplu:

(Trimiterea unui fișier prin socket)

procedura SendFileBySocket(nume fișier: șir) ;

var srcfile: TFileStream;

ÎNCEPE

(Deschideți numele fișierului)

Srcfile:= TFileStream.Create (nume fișier,fmOpenRead) ;

(Il trimitem primului client conectat)

ServerSocket1.Socket.Connections[0].SendStream(srcfile);

(Închide fișierul)

Srcfile.Free ;

Sfârşit ;

Trebuie remarcat faptul că metoda SendStream este folosită nu numai de server, ci și de client (ClientSocket1.Socket.SendStream(srcfile))
De ce pot fi combinate mai multe blocuri într-unul singur în timpul transmisiei?
Asta si la cererea lui JINX :-). Ii multumesc mult pentru asta! Deci, în primul rând, trebuie remarcat faptul că datele trimise printr-un socket nu pot fi combinate doar într-un singur bloc, ci și separate pe mai multe blocuri. Faptul este că un socket este un flux obișnuit, dar spre deosebire, de exemplu, de un flux de fișiere (TFileStream), transferă date mai lent (înțelegeți - rețea, trafic limitat etc.). De aceea două comenzi:
ServerSocket1.Socket.Connections.SendText("Bună ziua, ");
ServerSocket1.Socket.Connections.SendText("lumea!");
complet identic cu o singură comandă:
ServerSocket1.Socket.Connections.SendText("Bună, lume!");
Și de aceea, dacă trimiteți un fișier de, să zicem, 100 KB printr-un socket, atunci persoana căreia i-ați trimis acest bloc va primi mai multe blocuri cu dimensiuni care depind de trafic și aglomerația liniei. Mai mult, dimensiunile nu vor fi neapărat aceleași. Rezultă că, pentru a accepta un fișier sau orice alte date mari, ar trebui să acceptați blocuri de date și apoi să le combinați într-un singur întreg (și să salvați, de exemplu, într-un fișier). O soluție excelentă la această problemă este același flux de fișiere - TFileStream (sau un flux în memorie - TMemoryStream). Puteți primi date de la un socket prin evenimentul OnRead (OnClientRead) folosind metoda universală ReceiveBuf. Mărimea blocului primit poate fi determinată folosind metoda ReceiveLength. De asemenea, puteți utiliza un flux de socket (consultați articolul despre TClientSocket). Și iată un mic exemplu (aproximativ):

(Primește fișierul prin socket)

procedura TForm1.ClientSocket1Read (Expeditor: TObject ;

Socket: TCustomWinSocket);

var l: Integer ;

Buf: PChar ;

Src: TFileStream;

ÎNCEPE

(Scrieți în l dimensiunea blocului rezultat)

L:= Socket.ReceiveLength ;

(Memorie de comandă pentru buffer)

GetMem (buf,l+1);

(Scrieți blocul rezultat în buffer)

Socket.ReceiveBuf(buf,l);

(Deschideți un fișier temporar pentru scriere)

Src:= TFileStream.Create("fișierul meu.tmp" ,fmOpenReadWrite) ;

(Puneți poziția la sfârșitul fișierului)

Src.Seek (0 ,soFromEnd) ;

(Scrieți tamponul într-un fișier)

Src.WriteBuffer(buf,l);

(Închide fișierul)

Src.Free ;

(eliberarea memoriei)

FreeMem(buf);

Sfârşit ;

Cum să monitorizezi o priză
Această problemă este complexă și necesită o analiză îndelungată. Deocamdată, voi observa doar că puteți monitoriza oricând socket-ul creat de programul dvs. :-). Socket-urile (ca majoritatea obiectelor din Windows) au propriul mâner, scris în proprietatea Handle. Deci, odată ce recunoașteți acest descriptor, veți putea gestiona liber orice socket (chiar și unul creat de programul altcuiva)! Cu toate acestea, cel mai probabil, pentru a monitoriza socket-ul altcuiva, va trebui să utilizați exclusiv funcțiile WinAPI Sockets.
Epilog
Acest articol arată tehnicile de bază pentru lucrul cu componenta TServerSocket în Delphi și câteva tehnici generale pentru schimbul de date peste socketuri. Dacă aveți întrebări, trimiteți-mi-le pe e-mail: [email protected], și chiar mai bine - scrieți în conferința acestui site (Delphi. Întrebări generale) pentru ca alți utilizatori să vă vadă întrebarea și să încerce să vă răspundă!
Karikh Nikolay (Nitro). Regiunea Moscovei, Jukovski

Am adăugat suport de rețea. Adică a creat un server separat și un client separat. Ideea este că serverul de aplicații rulează, utilizatorul lansează clientul și introduce cererea în utilizator: Moscow Tverskaya 6. Apoi, serverul procesează cererea, primește rezultatele căutării de la Yandex.Maps și trimite imaginea rezultată către client, apoi în client, componenta TMap afișează o parte a unui card dat care se potrivește cu solicitarea utilizatorului. Ca rezultat, utilizatorul îl poate scala, îl poate salva și așa mai departe.

Prin urmare, în acest articol vreau să vă spun cum am implementat clientul și serverul. Am făcut acest lucru folosind TClientSocket și TServerSocket, în acest articol ne vom uita în detaliu la metodele pe care le-am folosit în proiectul meu.

Mai întâi, să vedem cum puteți instala aceste componente în IDE. Dacă utilizați IDE Delphi 7, atunci aceste componente sunt prezente implicit, dar, din păcate, nu sunt instalate, dar aceasta nu este o problemă. Trebuie doar să deschidem Delphi și să instalăm.

Pentru a face acest lucru, executați comanda Component-Install Packages... și în fereastra care apare, faceți clic pe butonul Adaugă. După aceasta, trebuie să specificați calea către fișierul dclsockets70.bpl, care se află de obicei în folderul BIN în mod implicit. După aceasta, trebuie să faceți clic pe butonul OK. Toate componentele dvs. ar trebui să apară în fila Internet (TClientSocket și TServerSocket).

În proiect, am început toată munca cu o dezvoltare minimă a serverului. Mai întâi, am instalat componenta TServerSocket pe formular. Și făcând clic pe butonul Start server am setat setările inițiale, pentru a-l inițializa:

Server. Port:=FormServerSetting. SpinEditPort. valoare; //specificați portul serverului Server. Activ: = Adevărat; //activează-l Server. Deschis ; dacă Server. Activ apoi începe //afișează un mesaj că serverul este pornit și rulează Sfârşit ; …….. //afișează o eroare dacă serverul nu a pornit

Pentru a inițializa serverul pe mașina mea, am specificat doar un port liber (care nu este ocupat de alte aplicații) și l-am activat.

În principiu, atât, pentru ca eu să lucrez, a fost suficient ca serverul să funcționeze și să pot procesa cererile clienților pe care le trimit.

Pentru a obține o listă de clienți care se conectează la server și a lucra în continuare cu ei, am instalat componenta TCheckListBox pe formular și pe evenimentul OnclientConnect al componentei TServerSocket, am scris următorul cod:

procedura TFormServer. ServerClientConnect (Expeditor: TObject; Socket: TCustomWinSocket) ; ÎNCEPE //monitorizează conexiunea clientului RichEditLog. SelAtribute. Culoare:=clGreen; RichEditLog. SelAtribute. Stil: = [fsBold]; CheckListClient. Articole. Adaugă (Socket.RemoteHost); RichEditLog. Linii. Adăugați ("[" + TimeToStr (Time) + "] Client conectat: " + Socket. RemoteHost ) ; //adăugați clientul care s-a conectat la listă RichEditLog. Efectuați (WM_VSCROLL, SB_BOTTOM, 0); Sfârşit ;

Adică adaug în listă numele acelor clienți care se conectează la server pentru a obține în continuare informații despre aceștia.

De exemplu, puteți obține informatii detaliate despre client:

procedura TFormInfoClient. FormShow(Expeditor: TObject); ÎNCEPE //afișează informații despre client Legendă: = „Informații despre client:”+FormServer. CheckListClient. Elemente[FormServer. CheckListClient. ItemIndex ] ; LocalName. Legendă: = FormServer. Server. Priză. Conexiuni[FormServer. CheckListClient. ItemIndex] . Gazdă locală ; Gazdă locală. Legendă: = FormServer. Server. Priză. Conexiuni[FormServer. CheckListClient. ItemIndex] . LocalAddress ; Local Port. Legendă: = IntToStr(FormServer. Server. Socket. Connections[ FormServer. CheckListClient. ItemIndex]. LocalPort); RemoteName. Legendă: = FormServer. Server. Priză. Conexiuni[FormServer. CheckListClient. ItemIndex] . Gazda la distanta ; Gazda la distanta. Legendă: = FormServer. Server. Priză. Conexiuni[FormServer. CheckListClient. ItemIndex] . RemoteAddress ; RemotePort. Legendă: = IntToStr(FormServer. Server. Socket. Connections[ FormServer. CheckListClient. ItemIndex]. RemotePort); Sfârşit ;

Se pot obtine urmatoarele date:

  • Nume local
  • Adresă locală
  • Port local
  • Nume eliminat
  • Adresă de la distanță
  • Port de la distanță

Primesc informații despre client folosind acest cod, pe care l-am selectat în lista componentei TCheckListBox.

După cum puteți vedea, nu este nimic complicat; pentru a trimite un mesaj clientului, puteți utiliza următorul cod:

ÎN paranteza patrata, specific la care client vom trimite mesajul (acesta este egal cu clientul selectat din componenta TCheckListBox), specific #message# în mesaj - ceea ce înseamnă că acesta este un mesaj normal de la server care ar trebui pur și simplu afișat La fereastră.

Pentru a primi un mesaj de la client către server, vom avea nevoie de evenimentul OnClientRead al componentei TServerSocket și de o variabilă text în care vom înregistra cererea pe care o trimite clientul.

procedura TFormServer. ServerClientRead(Expeditor: TObject; Socket: TCustomWinSocket) ; interogare var: String ; ÎNCEPE //primim o cerere de la client pentru cardîncercați interogarea: = Socket. ReceiveText ; if pos („interogare”, interogare)<>0 apoi începe //solicitare de la Yandex sau Coordonatele Google carduri conform cererii clientului Sfârşit ; //dacă este doar un mesaj de la client, atunci afișați-l dacă poziția („#mesaj#”, interogare)<>0 apoi începe sfârşitul ; ……

Din acest cod puteți vedea că clientul poate trimite atât un mesaj obișnuit către server, cât și o solicitare de a primi o hartă, cum ar fi: Moscova, Tverskaya, 6.

Pentru a face acest lucru, trebuie să stabilesc unde este mesajul obișnuit și unde este exact cererea de a primi un card, astfel încât serverul să îl poată procesa ulterior. În acest caz, adaug următorii identificatori la mesajele clientului chiar de la început:

  • #mesaj#
  • #interogare#

Dacă identificatorul #message# este prezent la începutul mesajului clientului, serverul îl recunoaște ca un mesaj obișnuit de la client. Dacă identificatorul #query# este prezent la începutul mesajului, aceasta înseamnă că clientul a trimis o solicitare pentru a primi un card.

De asemenea, un client se poate deconecta de la server în orice moment; de asemenea, trebuie să urmărim acest lucru pentru a-l elimina din lista generală de clienți conectați la server. Pentru a face acest lucru, selectați componenta TServerSocket și scrieți următorul cod în evenimentul OnClientDisconnect:

procedura TFormServer. ServerClientDisconnect (Expeditor: TObject; Socket: TCustomWinSocket) ; var i: întreg ; începe să încerci //monitorizează deconectarea clientului RichEditLog. SelAtribute. Culoare:=clRed; RichEditLog. SelAtribute. Stil: = [fsBold]; pentru i : = 0 la Server. Priză. ActiveConnections - 1 începe dacă Server. Priză. Conexiuni[i]. Mâner = Server. Priză. Conexiuni[i]. Gestionați apoi începeți RichEditLog. Linii. Adăugați ("[" + TimeToStr (Time ) + "] Client deconectat: " + Socket. RemoteHost ) ; CheckListClient. Articole. Ștergeți (i); RichEditLog. Efectuați (WM_VSCROLL, SB_BOTTOM, 0); Sfârşit ; Sfârşit ; in sfarsit //-//-//-//-//-// sfarsitul ; Sfârşit ;

Trecem prin toți clienții pe care îi avem în listă și dacă nu găsim unul, îl eliminăm din componenta TCheckListBox, asta înseamnă că clientul a făcut clic pe butonul Deconectare din aplicația sa.




Top