shoodyAdministrator
Postari: 46
|
|
Cum lucram cu socket-tii ?
Cred ca de multe ori va-ti intrebat cum lucreaza BO2K sau exploiturile !
Pai chiar asa de complicat asa nu poate fi ! hai sa vedem cum naiba se lucreaza cu socket-tii !
1. Ce este un socket ? Pai mai "babeste" spus este un canal de comunicatie !
Unu la mana exista mai multe tipuri de socketuri : 1. SOCK_STREAM : bidirectional , sigur 2. SOCK_DGRAM : bidirectional , nesigur (pachetele sar putea sa nu se mai intoarca 3. SOCK_RAW : folosit pentru "dedesupturi" 4. SOCK_PCK : cred ca este cel mai vechi (recomandabil a nu se folosi)
Doi la mana exista mai multe tipuri de domeni (ce fac domenile astea ? impun niste reguli de comunicatie socketurilor !)
1. AF_UNIX - domeniu de tip UNIX; 2. AF_INET - domeniu de tip Internet; 3. AF_RAW - domeniu de tip RAW
2. Cum cream un socket ?
connect = socket(domeniu,tip,protocol); Ex. Vrem sa cream un socket prin care sa ne putem lega la un port ! connect = socket(AF_INET,SOCK_STREAM,0); Easy ? Apropo connect este un integer care semnifica descriptorul . (da, da , exact ca la fisiere);
3. Cum asociem un nume socketului ?
Pentru identificare socketului de catre procese acesta are nevoie de un nume. Cand folosim domeniul internet (AF_INET) acest nume este compus din adresa masini server cat si cea a masini client cat si a porturilor lor .
Ex. bind(connect,nume,lungime nume)
4. Cum ne conectam ?
Depinde ce vrem sa facem .
Daca vrem client vom folosi functia connect : connect(descriptor, nume_socket, lungime_nume_socket); unde descripor este descriptorul socket-ului , nume_socket este socketul si lungime nume socket este sizeof(lungime_socket);
Daca vrem server folosim listen(decriptor,numar_conexiuni) unde descripor este descriptorul socket-ului iar numar connexiuni este numarul de conexiuni admise de server Ex. listen(connect,5); Dupa care folosim functia accept ca sa "acceptam" cererile catre server Ex. accept(connect,nume_socket, lungime_nume_socket);
5. Cum transmitem si receptionam date ?
Sub unix (mai precis sub linux) avem fucntile read si write ! sunt exact aceleasi functii pe care le folosim si la citirea si scrierea in fisiere! Sub windoze lucrurile se complica cam un pic dar nu mult ! Adica se folosesc alte 2 functii : send(connect,buffer,sizeof(buffer),flaguri); recv(connect,buffer,sizeof(buffer),flaguri);
unde flaguri reprezinta : MSG_PEEK - la un nou apel al functiei read() sau recv(), va fi citit din nou acelasi mesaj; MSG_OOB - este folosit pentru transmisia mesajelor cu prioritate maximă; MSG_DONTROUTE - trimite datele fără pachetele de rutare; (celelalte optiuni ale functilor send si recv sunt mura'n gura , nu ?
6. Cum inchidem un socket ?
O data cu close(connect); (exact ca la fisiere) sau cu shutdown(connect,tip de inchidere); unde tip de inchidere poate fi 0: nu se main pot citi date prin socket 1: nu se mai pot trimite date 2: nu se mai pot receptiona date
7. Practica : 1. Vom pune in practica un client care drept sa spun l-am facut pt. linux dar cred ca nu veti avea probleme sa il compilati si in Visual C++ (special am folosit functile send si recv)
2. Vedeti ca programul de fata nu a fost compilat niciodata Am facut si eu ceva reciclare de cod, am scris ceva de mana si uite ce o iesit
1. Exemplu de client:
#include #define PORT 23 #define MAXLINE 4096
client(int socket) { char recvline[MAXLINE],sendline[maxline]; for( ; ; ){ if (recv(socket,recvline,MAXLINE,0)==0){ printf("server terminated prematurely ! \n" ; exit(1); }
if (strncmp(recvline,"HALLO",5)==0){ strncpy(sendline,"Ce faci smechere ?",strlen("Ce faci smechere ?" ); // rea ii lenea asta )) send(socket,sendline,strlen(sendline),0); } } }
int main(int argc, char **argv) { int sockfd; struct sockaddr_in servaddr;
if (argc != 2) err_quit("usage: client " ; ifdef comentariu Creeam socketul ... endif
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
ifdef comentariu Dupa crearea socket-ului neconectam ! endif
connect(sockfd, (struct sockaddr_in *) &servaddr, sizeof(servaddr));
ifdef comentariu Predam socketul unei functii care stie ce sa faca cu el endif
client(sockfd); // in functa asta faceti numa send-uri si recv-uri
ifdef comentariu Inchidem socketul endif close(sockfd);
exit(0); }
Ok ! acuma sa dam drumu si la un server : (asta o fost compilat si o functionat perfect (sub linux) (Visual c++ cred eu ca nu stie de fork ! cred ca asta ar fi singurul inconvenient sub windows)
2. Exemplu de server :
#include #include #include #include #include #include #include #include #ifdef LINUX #include #endif
#define SERV_PORT 115
//#define DEBUG
void sig_chld(int signo) { pid_t pid; int stat;
pid = wait(&stat); printf("child %d terminated\n", pid); return; }
int main(void) { int listenfd, connfd; pid_t childpid; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; void sig_chld(int); char remotestring[512],check[32];
strcpy(remotestring,"SErVer Open and Ready\n" ; remotestring[22]=0; listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT);
bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
listen(listenfd, 1024);
signal(SIGCHLD, sig_chld);
for ( ; ; ) {
clilen = sizeof(cliaddr); if ( (connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen)) < 0) { if (errno == EINTR) continue; /* ianpoi la for */ else printf("accept error" ; }
if ( (childpid = fork()) == 0) { /* procesul copil */ send(connfd, remotestring, strlen(remotestring), 0); for(;{ recv(connfd, check, 511, 0); #ifdef DEBUG printf("check%s",check); #endif if (strncmp(check,"Close",5)==0) break;
if (strncmp(check,"Hallo",5)==0) send(co nnfd,"Hallo ! I am the server\n", 24, 0); }
close(listenfd); /* inchide socketul care asculta */ exit(0); } close(connfd); /* inchidem socketul parinte */
} by HACKMD
|
|