» Utilizator
LAMP
» Parteneri» De citit» Recomandari» Taskuri securitate » Statistici
  • 65486 de mesaje.
  • 7732 de topicuri.
  • 1230 de utilizatori.
  •  
  • Joistestisket8 e ultimul utilizator inregistrat.
[Detalii]

 

| |
Pagini: [1]
Print

[Curs C] - Lectia 11 - Utilizarea socketurilor [2502 afisari]

!_30
*


Mesaje: 1597
OfflineOffline


Dupa cum ati "observat" ,  din lectiile precedente , multe se pot face in C . Un lucru foarte important pentru un viitor programator "inrait" este Utilizarea socketurilor .

Pentru a putea "coda in voie" , trebuie intai sa intelegem notiunea de SOCKET .Voi recurge la un exemplu , din viata de zi cu zi , pentru aceasta.

Pentru a comunica cu colegul de banca la telefon ( din diverse motive ) , trebuie satisfacuti urmatori pasi : ( P.S. sa ai telefon ; iei telefonul , tastezi numarul -> suni si astepti ca respectivul sa raspunda ). Atat timp cat cei doi comunica  , doua parti opuse sunt implicate in proces , conectate una cu cealalta prin reteaua telefonica .

Care e asemanarea intre un SOCKET pe Linux si un telefon ? Socketii pot fi comparati cu telefoanele , fiind puncte "finale" de comunicatie.Pentru ca tu , sa suni pe cineva , trebuie sa stii numarul de telefon al respectivului si respectiv sa-l apelezi.Socketul este ca un telefonul ( are atasat o adresa  ) , pentru ca alt socket  , sa-l poate apela prin intermediul adresei respective , (prin reteaua de comunicatie).  


Acum putem trece serios pe codat  .

Stiti ca Linux este o "aglomerare de fisiere" si socketurile se aseamana mult cu fisierele . Precum si fisierele  , la crearea ( cu succes ) a  unui socket , acesta primeste descriptor ( socket descriptor ).




1.

Crearea socketurilor

Dupa cum spuneam mai devreme , socketurile returneaza un socket descriptor ( un numar ) , daca au fost create cu succes.Acesta le   identifica ).

Code:
int socket ( int domain , int type , int protocol )
La fel ca si functia open() ( care creaza un "descriptor de fisier" pentru a putea accesa/gasi fisierele / device-urile din sistem ) , asa si ]socket()    creaza un socket descriptor pentru a accesa computerele din retea/Internet  . Frumoasa analogie , nu ?
 
Va intrebati ce reprezinta notatiile de mai sus :

domain = domeniul socketului .Adica ?
* local : comunicare intre socketuri la nivel local ( pe PC-ul pe care se ruleaza programul )
* Internet : stackul TCP/IP , IPX , Rose , Apple, pentru comunicare intre socketuri pe retea / Internet ( va aduceti aminte de exemplul telefoanelor ).  

                                         *PF_INET
                                         *PF_LOCAL
                                         *PF_INET6
                                         *PF_IPX
                                         *PF_APPLETALK

type = tipul socketului , cam ciudat nu ? Hint : cum se face transferul de date .

                                         *SOCK_STREAM
                                         *SOCK_DGRAM
                                         *SOCK_RAW

protocol = pentru inceput il consideram 0.

Un exemplu ar fi bun .


Code:
int sock;
sock = socket  ( PF_INET,SOCK_STREAM,0);
Ce se intampla defapt ? Se deschide un socket ( de comunicare ) cu urmatoarele propietati. Socketul va face comunicarea pe Internet , intre terminale ( PC-uri remote ) .

* PF_INET semnifica acest lucru ( comunicarea pe Internet ).
*-SOCK_STREAM e metoda de transmisie de date , aici prin TCP. Metoda reliabila de transfer date vs
*- SOCK_DGRAM , metoda folosind UDP , nereliabila ( daca datele se pierd , nu se mai ocupa cu retransmisia) .
*Integerul sock , este     descriptul de socket.Acesta identifica socketul pentru a putea fi folosit la schimbul de date.



De retinut : Daca valoarea descriptorului ( care este un integer ) e negativa ( < 0 )   , socketul nu a fost creat .
Daca e pozitiva , socketul a fost creat cu succes. Aceasta e bine de stiut , daca lucram "intens" si avem nevoie sa ne ocupam de toate erorile.Desigur sunt niste functii / variabile predefinite , pentru lucrul cu erorile .  

Putem folosi pentru asta codul simplu de mai jos . Creem un socket de Internet , transmisie date reliabila ( TCP ).

Code:
int sock;

sock = socket (PF_INET , SOCK_STREAM , 0 );
if sock < 0
       printf(" Error " );
Mai jos este un cod minimal de atribuire date ( adresa / port / tip ) unui socket . Acestea sunt valorile la care poate fi contactat. ( numarul de telefon ).



2. Adresa socket

Code:
struct sockaddr_in adr_inet; /* structura tipul de date adresa , etc ..*/


adr_inet.sin_family=AF_INET;
adr_inet.sin_port=htons(130);
adr_inet.sin_addr.s_addr = htonl(INADDR_ANY);
Cum  v-ati dat bine seama , aceste detalii arata tipul , portul si adresa ( aici INADDR_ANY , orice adresa ) la care poate fi contactat socketul .

* AF_INET : semnifica ca acest socket , va fi folosit pentru schimb date cu alte socketuri la nivel retelistic , Internet , nu la nivel local.

* 130 : portul  local , la care serverul va accepta conexiuni  .
-valoarea 0 , va alege un port aleatoriu , nu unul prestabilit. ( gen 130  . ca mai sus ).
   
INADDR_ANY : semnifica , ca socketul isi primeste conexiuni  pe toate IP-urile ( computerului local ) .De preferat e sa punem un IP prestabilit , pentru o mai buna comunicare fara de eroare Big grin




3. BIND :

Aveti un exemplu mai jos :

Code:
int z;

(z = bind (sock,(struct sockaddr * )&adr_inet,sizeof(adr_inet)) < 0 )
                printf("  ERROR ");
BIND() primeste ca valoare un integer ( int ) . Cum va dati seama daca e negativ , nu s-a "bindat" ( atasat adresa de socket )  cu succes.
- are ca parametri , sock-ul , (SOCKETUL) , pe care l-am declarat mai sus ; adresa acestuia ( ii bindam , alipim socketului adresa si detaliile respective ) , si lungimea adresei .

BIND() , cum ii zice si numele , lipeste ( adresa / port / tip ) de socket .
-rostul lui ? : uneori este cu adevarata nevoie ( pentru anumite servicii si nu numai ) ca un server sa aiba alipit un anumit port / adresa pentru a se face schimbul "corect" de informatii.  



4. LISTEN()  

- acesta defineste cate conexiuni simultane va accepta socketul creat.

Code:
listen(sock,5);
Deci dupa cum va dati seama , socketul creat de noi mai devreme , va accepta maxim 5 conexiuni simultane
- cei doi parametri :  primul socketul , al doilea numarul de conexiuni simultane , maxim acceptate.


5. CONNECT()

-conectarea la un socket remote ( stiind datele respectivului ) ,eventual  pentru un schimb de informatii.
Clienti se conecteaza la servere Tongue , serverele asculta  LISTEN ()  si accepta conexiuni   ACCEPT () . E bine de stiut , in ce parte a codului ( sursa sau client ) se vor prezenta functiile / call-urile de sistem pe care le prezint.

Code:

if( connect(sock,(struct sockaddr *) &server, sizeof(server)) < 0){

                                                          printf("Eroare la conectare");
- connect primeste ca parametri , socketul ( prin care se face conexiunea ) , datele ( adresa / port / detalii ) unde se face conexiunea . Daca acesta e negativ , conexiunea nu s-a putut efectua ( din anumite motive . EX : serverul nu mai accepta conexiuni .)



6. ACCEPT

Spuneam mai devreme ceva de ACCEPT () . Acesta apare in partea server a programului , si accepta conexiuni de la clientul.
-clientul incearca CONNECT() , (sa se conecteze)  ,  serverul il asculta [ LISTEN() si accepta ACCEPT() ]. Simplu , nu ? Sa vedem sintaxa.

Code:


 lc =   sizeof(struct sockaddr_in);

        if( (sc = accept(sock, (struct sockaddr *) &adr_inet ,&lc)) < 0)
                                          {
                                                  printf("Eroare la acceptarea conexiunii");

                                          }
-serverul accepta conexiuni , pe socketul sock (creat mai sus) ,cu propietatile adr_inet ( adresa/ port / etc ) .
-daca e negativ , acesta nu a putut accepta conexiunea , (poate fi din motive tehnice , sau nu mai asculta , deoarece s-a incarcat deja numarul maxim de conexiuni simultane de la LISTEN().)


Deci practic , pana acum , ce am facut . Recapitulam :

*creare socket
*atribuire adresa/port  socketului
*BIND() adresa/port socketului ( Optional )
*LISTEN () accepta conexiuni serverul
*CONNECT() : conectare client - server
*ACCEPT() : accepta conexiuni serverul de la client



Ce mai ramane de facut ? Schimbul practic de informatii Smile
Vom exemplifica , prin trimiterea de la server  a stringului "Hello World" , catre client .


Sunt mai multe functii de trimitere si primire de mesaje : SEND() vs RECV() . Le voi prezenta eu minal mai jos.



7. SEND()

Code:
 gets(buffer);
  send(sock,buffer,bufsize,0);
Dupa cum observati , nu am mai dat sintaxa , ci am trecut direct la exemplu .
- se citeste un sir de caractere ( declarat buffer ) , apoi se trimite socketului remote ( server/client ).
SEND() primeste ca parametri , socketul : prin care se trimite ( cuprinde valorile / datele adresa port , unde va ajunge informatia ) , mesajul de trimis ( stringul buffer ) si bufsize ( numarul de caractere ale stringului ).Se poate calcula usor cu functia strlen(buffer) ).



8. RECV()

Acesta primeste sirul de caractere  trimis de client / server , si la comanda noastra , poate sa fie afisat mesajul pe ecran , sau scris intr-un fisier  sau cine stie ce altceva se poate face ( depinde  de voi ).

Code:
 recv(sock,buffer,bufsize,0);
Are aceeasi sintaxa ca SEND() , doar ca aici nu se mai citeste bufferul , ci este primit de la socketul "remote" , care l-a trimis mai sus.




Sper ca am reusit , desi nu cred ( ca se poate in numai o lectie ) , sa va dau o tenta a ce inseamna Utilizarea socketurilor .Voi prezenta  intr-o extensie aferenta acestei lectii , cateva exemple practice  de client - server , care folosesc functiile de mai sus.Poate veniti chiar voi cu exemple , dar si cu intrebari . ( P.S. : voi mai bibili aceasta lectie , deoarece cred ca la prima mana sigur am scapari ).


Cheer's ! :read2:
Logged
17-10-2006, 14:48 Twitt ::
3Nigma
*


Mesaje: 1617
OfflineOffline

WWW

bv dude...vad ca esti wiz la retele! 8)
Logged

17-10-2006, 15:20 Twitt ::
Agkelos
*


Mesaje: 7196
OfflineOffline

WWW

Nu vreau sa fiu carcotas, dar ai putea sa recitesti cursul si sa rescrii unele fraze ? Sa fie mai "cursiva" toata treaba. As vrea ca dupa ce se termina toate lectiile din curs sa pun totul intr-un PDF (cu creditele cuvenite, bineinteles) si ordonarea ideilor m-ar scuti de muuuulta treaba la capitolul Q.C. Big grin
Logged

17-10-2006, 15:38 Twitt ::
!_30
*


Mesaje: 1597
OfflineOffline


Asta am incerat "indirect" in mai josul cursului sa mentionez.Ca va mai fi bibilit , deoarece am impresia ( sigur ) , si eu is carcotas , ca unele fraze cam "o iau razna".

I'll take care !  :headbang:
Logged
17-10-2006, 15:40 Twitt ::
R3AL
*


Mesaje: 48
OfflineOffline

WWW

o intrebare, care este numarul maxim de socket-uri deschise suportate de un program in C/C++/C# ? este o limita ? Thinking
Logged

27-08-2007, 19:39 Twitt ::
redkar23
*


Mesaje: 164
OfflineOffline

WWW

Da ,este o limita. Dar variaza de la OS la OS  si limita este influentzata de memoria HDD ,din cate imi amintesc. Oricum , nu cred ca apuci sa deschizi simultan atatea socketuri ca sa omori programul  :cool:

 Cheers
Logged
27-03-2008, 20:47 Twitt ::
danieLs
*


Mesaje: 569
OnlineOnline

WWW

Quote from: R3AL
o intrebare, care este numarul maxim de socket-uri deschise suportate de un program in C/C++/C# ? este o limita ? Thinking
65535 ? nu stiu sigur, dar asa cred, adica ca sa deschizi un socket (tcp/ip) iti trebuie un port, si numarul maxim de porturi e 65535...
I don't know
Logged

The only valid measurement of code quality is: WTF's/minute

(\__/)
(+'.'+) This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
27-03-2008, 22:26 Twitt ::
astan
*


Mesaje: 773
OfflineOffline


Nu, numarul maxim depinde de sistemul de operare folosit.
In linux cand un process deschide un socket, socket-ului i se aloca un file descriptor din array-ul de file descriptori disponibili asociati procesului.
Ca sa vedeti numarul maxim de fisiere ce pot fi deschise:
%>cat /proc/sys/fs/file-max

Respectivul parametru este desigur configurabil prin sysctl
%> sysctl -w fs.file-max=new_max

Un socket poate sa fie deschis folosind protocolul AF_UNIX, nu numai AF_INET.
Daca este AF_UNIX inseamna ca va fi folosit pentru comunicarea intre procese pe aceeasi masina si nu va fi legat de un port anume, insemnand ca nu exista nici o legatura intre numarul de socket-uri ce poate fi deschis si numarul maxim de porturi disponibile

Valoarea default pentru file-max este setata in kernel la 8192:

linux/fs/file_table.c
/* sysctl tunables... */
  27struct files_stat_struct files_stat = {
  28        .max_files = NR_FILE
  29};

unde NR_FILE este definit in  linux/include/linux/fs.h:
#define NR_FILE  8192

Dar, precum am spus, ea poate fi modificata la runtime utilizand sysctl.
8192 e doar setata orientativ la compile time (al kernelului)
Logged
27-03-2008, 23:25 Twitt ::
danieLs
*


Mesaje: 569
OnlineOnline

WWW

ok, dar daca protocolul este AF_INET eu tot cred ca numarul maxim de soketuri deschise simultan este 65535
Logged

The only valid measurement of code quality is: WTF's/minute

(\__/)
(+'.'+) This is Bunny. Copy and paste bunny into
(")_(") your signature to help him gain world domination.
28-03-2008, 07:32 Twitt ::
redkar23
*


Mesaje: 164
OfflineOffline

WWW

da, pe AF_INET ar fi maxim 65535 ( unsigned int ). Doar ca am citit undeva ca numarul difera si daca foloseste numai AF_INET. like , win95 ( absurd ,dar nah, se ia in considerare ) , win 98 , win ME , NT , 2000, XP  , pentru fiecare e un numar maxim diferit admis, cam asa : cu cat e mai vechi sistemul, cu cat maximul este mai mic.
    Nu stiu sigur. doar am citit undeva. nu am apucat sa testez Laughing


 Cheers Smile
Logged
28-03-2008, 17:13 Twitt ::
Pagini: [1]
Print
SkullBox Forum  |  Development  |  Java / C / C++ / C#  |  Topic: [Curs C] - Lectia 11 - Utilizarea socketurilor