» Utilizator
Salut, vizitatorule!

SkullBox este o comunitate formata din programatori si administratori de sisteme sau retele care iti sta la dispozitie cand ai o problema legata de calculatoare. Daca esti un utilizator existent, autentifica-te.

Daca nu te-ai inregistrat inca pe forum, alatura-te noua astfel marind comunitatea si ajutandu-i pe cei care au nevoie de informatii.

Daca te-ai inregistrat dar inca nu ai primit codul de activare, il poti cere aici.




Autentifica-te cu numele de utilizator si parola pentru a putea posta pe forum sau pentru a accesa ariile disponibile doar utilizatorilor inregistrati.
 » Concurs
GameDev
 » Statistici
  • 46957 de mesaje.
  • 5871 de topicuri.
  • 825 de utilizatori.
  •  
  • cdoryn74 e ultimul utilizator inregistrat.
[Detalii]

 » Parteneri » Sponsori

 » Recomandăm
HostVision

» Avem un concurs pentru bloggeri si forumisti. Participi? «
Pagini: [1]
Print
[Curs C] - Lectia 11 - Utilizarea socketurilor [1896 afisari]
!_30
*


Mesaje: 1009
OfflineOffline

WWW

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

It's not our abilities that show who we truly are, it's our choices.
17-10-2006, 14:48 
 
3Nigma
*


Mesaje: 981
OfflineOffline

WWW

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

Search for knowledge in the darkest places and in the blackest hours! You might get lucky and find more than you are looking for...

"Ambition is a lame excuse for the ones that are not brave enough to be lazy..."
17-10-2006, 15:20 
 
Agkelos
*


Mesaje: 6024
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

Blog | Twitter

De nu va zice omul intru inima sa "Eu singur si Dumnezeu suntem in lume" nu va avea odihna. - Avva Alonie
17-10-2006, 15:38 
 
!_30
*


Mesaje: 1009
OfflineOffline

WWW

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

It's not our abilities that show who we truly are, it's our choices.
17-10-2006, 15:40 
 
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 
 
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


What doesn't kill you, makes you stronger .       - Friedrich Nietzsche
O noua definitie a ironiei : life itself .                 - Redkar23
27-03-2008, 20:47 
 
danieLs
*


Mesaje: 433
OfflineOffline

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 
 
astan
*


Mesaje: 535
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 
 
danieLs
*


Mesaje: 433
OfflineOffline

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 
 
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


What doesn't kill you, makes you stronger .       - Friedrich Nietzsche
O noua definitie a ironiei : life itself .                 - Redkar23
28-03-2008, 17:13 
Pages: [1]
Print
SkullBox Forum  |  Development  |  Java / C / C++ / C# (Moderators: AnaKonD, astan)  |  Topic: [Curs C] - Lectia 11 - Utilizarea socketurilor
Jump to: