Programare socket în C++

Programare Socket In C



Programarea socket-urilor a devenit un subiect important în domeniul rețelelor de calculatoare. Aceasta implică stabilirea unei conexiuni între două noduri, server și client pentru a comunica între ele fără nicio întrerupere. Serverul acționează ca un ascultător în canalul de comunicare și ascultă clientul pe un anumit port la o adresă IP. Pe de altă parte, clientul acționează ca un comunicator în canalul de comunicare. Clientul contactează serverul pentru a crea o conexiune și a lua legătura cu serverul. Acest articol își propune să ofere un ghid cuprinzător și detaliat pentru programarea socketului în C++, acoperind elementele de bază, prezentând exemple practice și oferind o explicație detaliată a codului.

Stabilirea modelului client-server

Programarea socketului este procesul care construiește un canal de comunicare între server și client folosind socket-uri. În următorul exemplu de cod, clientul începe un contact cu serverul, iar serverul este configurat să accepte conexiunile client. Să înțelegem segmentele de cod de server și client, demonstrând funcționarea de bază a acestora în comunicarea în rețea. Următorul este codul de pe partea serverului. Să vedem mai întâi codul și apoi să explicăm codul în detaliu, punct cu punct.

1. Partea serverului







Codul pentru partea de server a modelului este dat în cele ce urmează. Să vedem ce se întâmplă în cod:



#include
#include
#include
#include

folosind spatiu de nume std ;

#define PORT 8080
#define MAX_BUF_SIZE 1024

int principal ( ) {
int ser_socket, cli_socket ;
struct sockaddr_in ser_address, cli_address ;
char buf [ MAX_BUF_SIZE ] = { 0 } ;

dacă ( ( ser_socket = priză ( AF_INET, SOCK_STREAM, 0 ) ) == - 1 ) {
groază ( „Eroare la crearea socketului” ) ;
Ieșire ( EXIT_FAILURE ) ;
}

ser_address. sin_family = OF_INET ;
ser_address. sin_addr . s_adr = INADDR_ANY ;
ser_address. sin_port = htoni ( PORT ) ;

dacă ( lega ( fi_socket, ( struct sockaddr * ) & ser_address, dimensiunea ( ser_address ) ) == - 1 ) {
groază ( „Eșec în legătură” ) ;
Ieșire ( EXIT_FAILURE ) ;
}

dacă ( asculta ( fi_socket, 3 ) == - 1 ) {
groază ( „Eșuat să ascult” ) ;
Ieșire ( EXIT_FAILURE ) ;
}

cout << „Serverul ascultă pe port” << PORT << „... \n ' ;

socklen_t cli_address_len = dimensiunea ( adresa_cli ) ;
dacă ( ( cli_socket = Accept ( fi_socket, ( struct sockaddr * ) & adresa_cli, & cli_address_len ) ) == - 1 ) {
groază ( „Nu am acceptat” ) ;
Ieșire ( EXIT_FAILURE ) ;
}

citit ( cli_socket, buf, MAX_BUF_SIZE ) ;
cout << 'Mesajul clientului este: ' << buf << endl ;

trimite ( cli_socket, 'Mesajul serverului' , strlen ( 'Mesajul serverului' ) , 0 ) ;

închide ( cli_socket ) ;
închide ( ser_socket ) ;

întoarcere 0 ;
}

Exemplul dat este codul server-side al programului C++. Acest cod funcționează pentru un server TCP simplu pentru a asculta conexiunile pe un singur port specific. Când o conexiune este creată cu succes, serverul va primi un mesaj care este trimis de la client. După aceea, îl imprimă pe consolă și trimite un mesaj de răspuns clientului. Să înțelegem fiecare linie de cod.



Programul începe cu includerea bibliotecilor: „iostream” pentru definițiile standard de intrare/ieșire, „cstring” pentru funcțiile de gestionare a șirurilor, „unistd.h” pentru a oferi acces la API-ul sistemului de operare POSIX și „arpa/inet.h” la efectuează operațiunile pe internet. Declarația „#define PORT 8080” înseamnă că definește numărul portului 8080 pe care serverul va asculta. „#define MAX_BUF_SIZE 1024” înseamnă dimensiunea maximă a memoriei tampon pentru datele primite, care este 1024.





În funcția principală sunt inițializate două variabile, „ser_socket” și „cli_socket”, pentru a reprezenta atât serverul, cât și respectiv clientul. Celelalte trei variabile care sunt „sockaddr_in”, „ser_address” și „cli_address” de tip „struct” sunt inițializate ca structuri de adrese pentru server și client. După aceea, este inițializat un buffer numit „buf” care stochează datele care provin de la client.

Funcția socket() în condiția „dacă” creează un nou socket TCP. AF_INET denotă IPv4, SOCK_STREAM reprezintă socket-ul TCP de încredere și orientat spre conexiune, ultimul argument care este 0 este dat pentru a selecta protocolul TCP implicit, INADDR_ANY acceptă conexiunile pe orice adresă IP, iar htons (PORT) convertește numărul portului din ordinea octeților gazdei la ordinea octeților rețelei.



Deoarece totul este definit corect, următorul pas este să configurați serverul ca listă pe portul dat și să acceptați conexiunile pe orice interfață de rețea. Socket-ul este dat cu informațiile din „ser_address” prin metoda bind(). Tipărim o eroare și încheiem procesul dacă legarea eșuează. Funcția accept() deschide o nouă soclu pentru conexiunea cu clientul, în timp ce funcția listen() instruiește serverul să aștepte conexiunile de intrare. Dacă funcția accept() eșuează, mesajul de eroare este tipărit și funcția va ieși.

Apoi, serverul citește mesajul clientului cu funcția read() în buffer-ul „buf” și apoi îl imprimă pe consolă. Funcția send() este folosită de server pentru a trimite un mesaj ca răspuns către client. În cele din urmă, folosind close(), serverul închide socket-ul clientului, terminând programul, astfel încât toate conexiunile să fie închise corect și să nu existe probabilitatea de încălcare a datelor.

2. Partea clientului

Acum, să vedem ce se întâmplă în modelul client:

#include
#include
#include
#include

#define PORT 8080
#define SERVER_IP „127.0.0.1”

int principal ( ) {
int cli_socket ;
struct sockaddr_in ser_address ;
const char * mesaj = „Clientul trimite salutări!” ;

dacă ( ( cli_socket = priză ( AF_INET, SOCK_STREAM, 0 ) ) == - 1 ) {
groază ( „Eroare la crearea soclului” ) ;
Ieșire ( EXIT_FAILURE ) ;
}

ser_address. sin_family = OF_INET ;
ser_address. sin_port = htoni ( PORT ) ;

dacă ( inet_pton ( AF_INET, SERVER_IP, & ser_address. sin_addr ) <= 0 ) {
groază ( 'Adresă greșită' ) ;
Ieșire ( EXIT_FAILURE ) ;
}

dacă ( conectați ( cli_socket, ( struct sockaddr * ) & ser_address, dimensiunea ( ser_address ) ) == - 1 ) {
groază ( „Eșec de conexiune” ) ;
Ieșire ( EXIT_FAILURE ) ;
}
trimite ( cli_socket, mesaj, strlen ( mesaj ) , 0 ) ;

char buf [ 1024 ] = { 0 } ;
citit ( cli_socket, buf, dimensiunea ( buf ) ) ;
std :: cout << 'Răspunsul serverului: ' << buf << std :: endl ;

închide ( cli_socket ) ;
întoarcere 0 ;
}

Să vedem fiecare linie de cod pentru a înțelege cum funcționează programul.

Aceleași patru biblioteci – iostream, cstring, unistd.h și arpa/inet.h – sunt, de asemenea, incluse pe partea clientului. Un număr de port este, de asemenea, definit împreună cu adresa IP a gazdei locale 127.0.0.1. Este dat mesajul care trebuie livrat serverului. Clientul și serverul trebuie să stabilească o conexiune după următorul pas:

„dacă ((client_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1);” creează un socket pentru IPv4 cu un tip de flux și protocolul implicit TCP. Perror() afișează detaliile erorii dacă funcția socket() nu reușește să stabilească o conexiune și iese din program.

„Server_address.sin_port = htons(PORT);” setează numărul portului după conversia în ordinea octeților de rețea. Ulterior, un alt mesaj de eroare care este „Adresa greșită” este dat aici, care este tipărit dacă există ceva în neregulă cu adresa. Prin localizarea adresei în „ser_address”, clientul se va conecta la server. Dacă conexiunea eșuează, detaliile erorii sunt tipărite. Funcția send() va transfera mesajul către server, asigurându-se că nu conține niciun flag.

Pentru a primi și stoca un răspuns de la server, este inițializat un buffer numit „buf” de tip „char”. Funcția read() citește răspunsul serverului în buffer. În cele din urmă, răspunsul serverului este imprimat pe consolă. În cele din urmă, conexiunea este închisă folosind instrucțiunea close() pentru a termina socket-ul. Următorul este rezultatul programului:

Concluzie

Programarea socketului este o parte importantă a comunicării în rețea în informatică. Permite dezvoltarea de aplicații care pot comunica prin rețea, permițând o gamă largă de posibilități, de la arhitecturi simple client-server până la sisteme structurate distribuite. Când un socket este creat într-un context de programare, programul trebuie să-și configureze caracteristicile punctului final, cum ar fi protocoalele, TCP sau UDP și adresa de rețea, cum ar fi adresa IP și numărul portului. Aceste prize permit serverelor să trimită și să primească datele. Acest articol demonstrează un exemplu practic despre cum funcționează modelul client-server în programarea socketului.