Socket programavimas C++

Socket Programavimas C



Socket programavimas tapo svarbiu dalyku kompiuterių tinklų srityje. Tai apima ryšio tarp dviejų mazgų, serverio ir kliento užmezgimą, kad būtų galima bendrauti tarpusavyje be jokių trukdžių. Serveris veikia kaip klausytojas ryšio kanale ir klauso kliento konkrečiame prievade IP adresu. Kita vertus, klientas komunikacijos kanale veikia kaip komunikatorius. Klientas susisiekia su serveriu, kad užmegztų ryšį ir užmegztų ryšį su serveriu. Šiuo straipsniu siekiama pateikti išsamų ir išsamų lizdų programavimo C++ kalboje vadovą, apimantį pagrindus, praktinius pavyzdžius ir išsamų kodo paaiškinimą.

Kliento-serverio modelio sukūrimas

Socket programavimas yra procesas, kurio metu sukuriamas ryšio kanalas tarp serverio ir kliento naudojant lizdus. Šiame pavyzdiniame kode klientas pradeda susisiekti su serveriu, o serveris yra nustatytas priimti kliento ryšius. Leiskite mums suprasti serverio ir kliento kodo segmentus, parodydami jų pagrindinį darbą tinklo komunikacijoje. Toliau pateikiamas serverio kodas. Pirmiausia pamatykime kodą, o tada išsamiai, taškas po taško, paaiškinkime kodą.

1. Serverio pusė







Toliau pateikiamas modelio serverio pusės kodas. Pažiūrėkime, kas vyksta kode:



#include
#include
#include
#include

naudojant vardų erdvė std ;

#define PORT 8080
#define MAX_BUF_SIZE 1024

tarpt pagrindinis ( ) {
tarpt ser_socket, cli_socket ;
struktūra sockaddr_in ser_address, cli_address ;
char buf [ MAX_BUF_SIZE ] = { 0 } ;

jeigu ( ( ser_socket = lizdas ( AF_INET, SOCK_STREAM, 0 ) ) == - 1 ) {
klaidą ( „Klaida kuriant lizdą“ ) ;
išeiti ( EXIT_FAILURE ) ;
}

ser_adresas. nuodėmės_šeima = OF_INET ;
ser_adresas. sin_addr . s_addr = INADDR_ANY ;
ser_adresas. sin_port = htonai ( UOSTAS ) ;

jeigu ( įpareigoti ( be_socket, ( struktūra sockaddr * ) & ser_adresas, dydis ( ser_adresas ) ) == - 1 ) {
klaidą ( „Surišimo gedimas“ ) ;
išeiti ( EXIT_FAILURE ) ;
}

jeigu ( klausyk ( be_socket, 3 ) == - 1 ) {
klaidą ( „Nepavyko klausytis“ ) ;
išeiti ( EXIT_FAILURE ) ;
}

cout << 'Serveris klausosi prievade' << UOSTAS << '... \n ;

socklen_t cli_address_len = dydis ( cli_adresas ) ;
jeigu ( ( cli_socket = priimti ( be_socket, ( struktūra sockaddr * ) & cli_address, & cli_address_len ) ) == - 1 ) {
klaidą ( 'Nepavyko priimti' ) ;
išeiti ( EXIT_FAILURE ) ;
}

skaityti ( cli_socket, buf, MAX_BUF_SIZE ) ;
cout << „Kliento pranešimas yra: << buf << endl ;

siųsti ( cli_socket, 'Serverio pranešimas' , strlen ( 'Serverio pranešimas' ) , 0 ) ;

Uždaryti ( cli_socket ) ;
Uždaryti ( ser_socket ) ;

grąžinti 0 ;
}

Pateiktas pavyzdys yra C++ programos serverio kodas. Šis kodas tinka paprastam TCP serveriui, kad būtų galima klausytis jungčių viename konkrečiame prievade. Sėkmingai užmezgus ryšį, serveris gaus pranešimą, siunčiamą iš kliento. Po to jis išspausdina jį konsolėje ir išsiunčia atsakymo pranešimą klientui. Supraskime kiekvieną kodo eilutę.



Programa pradedama įtraukiant bibliotekas: „iostream“ standartiniams įvesties / išvesties apibrėžimams, „cstring“ eilučių tvarkymo funkcijoms, „unistd.h“ suteikia prieigą prie POSIX operacinės sistemos API ir „arpa/inet.h“ atlikti interneto operacijas. Teiginys „#define PORT 8080“ reiškia, kad jis apibrėžia prievado numerį 8080, kurio serveris klausys. „#define MAX_BUF_SIZE 1024“ reiškia maksimalų gaunamų duomenų buferio dydį, kuris yra 1024.





Pagrindinėje funkcijoje inicijuojami du kintamieji: „ser_socket“ ir „cli_socket“, kad būtų atitinkamai nurodytas serveris ir klientas. Kiti trys kintamieji „sockaddr_in“, „ser_address“ ir „cli_address“ tipo „struct“ inicijuojami kaip serverio ir kliento adresų struktūros. Po to inicijuojamas buferis, pavadintas „buf“, kuriame saugomi iš kliento gaunami duomenys.

Socket() funkcija esant sąlygai „if“ sukuria naują TCP lizdą. AF_INET žymi IPv4, SOCK_STREAM reiškia į ryšį orientuotą ir patikimą TCP lizdą, paskutinis argumentas, kuris yra 0, suteikiamas norint pasirinkti numatytąjį TCP protokolą, INADDR_ANY priima ryšius bet kokiu IP adresu, o htons (PORT) konvertuoja prievado numerį iš pagrindinio kompiuterio baitų tvarka į tinklo baitų tvarką.



Kadangi viskas apibrėžta tinkamai, kitas žingsnis yra nustatyti serverį kaip sąrašo sąrašą nurodytame prievade ir priimti ryšius bet kurioje tinklo sąsajoje. Lizdas pateikiamas su „ser_address“ informacija, naudojant bind() metodą. Išspausdiname klaidą ir užbaigiame procesą, jei įrišimas nepavyksta. Funkcija accept() atidaro naują lizdą ryšiui su klientu, o funkcija listen() nurodo serveriui laukti gaunamų ryšių. Jei akcept() funkcija nepavyksta, išspausdinamas klaidos pranešimas ir funkcija išjungiama.

Tada serveris nuskaito kliento pranešimą su funkcija read() į buferį „buf“ ir išspausdina jį į konsolę. Funkciją send() serveris naudoja, kad išsiųstų pranešimą klientui. Galiausiai, naudojant close(), serveris uždaro kliento lizdą, nutraukdamas programą, kad visi ryšiai būtų tinkamai uždaryti ir nebūtų duomenų pažeidimo tikimybės.

2. Kliento pusė

Dabar pažiūrėkime, kas vyksta kliento modelyje:

#include
#include
#include
#include

#define PORT 8080
#define SERVER_IP '127.0.0.1'

tarpt pagrindinis ( ) {
tarpt cli_socket ;
struktūra sockaddr_in ser_address ;
konst char * žinutę = 'Klientas siunčia sveikinimus!' ;

jeigu ( ( cli_socket = lizdas ( AF_INET, SOCK_STREAM, 0 ) ) == - 1 ) {
klaidą ( „Klaida kuriant lizdą“ ) ;
išeiti ( EXIT_FAILURE ) ;
}

ser_adresas. nuodėmės_šeima = OF_INET ;
ser_adresas. sin_port = htonai ( UOSTAS ) ;

jeigu ( inet_pton ( AF_INET, SERVER_IP, & ser_adresas. sin_addr ) <= 0 ) {
klaidą ( 'Neteisingas adresas' ) ;
išeiti ( EXIT_FAILURE ) ;
}

jeigu ( Prisijungti ( cli_socket, ( struktūra sockaddr * ) & ser_adresas, dydis ( ser_adresas ) ) == - 1 ) {
klaidą ( 'Ryšio sutrikimas' ) ;
išeiti ( EXIT_FAILURE ) ;
}
siųsti ( cli_socket, žinutė, strlen ( žinutę ) , 0 ) ;

char buf [ 1024 ] = { 0 } ;
skaityti ( cli_socket, buf, dydis ( buf ) ) ;
std :: cout << 'Serverio atsakymas:' << buf << std :: endl ;

Uždaryti ( cli_socket ) ;
grąžinti 0 ;
}

Pažiūrėkime kiekvieną kodo eilutę, kad suprastume, kaip programa veikia.

Tos pačios keturios bibliotekos – iostream, cstring, unistd.h ir arpa/inet.h – taip pat įtrauktos į kliento pusę. Prievado numeris taip pat apibrėžiamas kartu su vietinio pagrindinio kompiuterio IP adresu 127.0.0.1. Pateikiamas pranešimas, kuris turi būti pristatytas į serverį. Klientas ir serveris turi užmegzti ryšį taip:

„if ((kliento_socket = lizdas(AF_INET, SOCK_STREAM, 0)) == -1); sukuria IPv4 lizdą su srauto tipu ir numatytuoju TCP protokolu. Perror () išspausdina išsamią klaidos informaciją, jei socket () funkcijai nepavyksta užmegzti ryšio ir išeiti iš programos.

„serverio_adresas.sin_port = htons(PORT);“ nustato prievado numerį konvertavus į tinklo baitų tvarką. Po to čia pateikiamas kitas gedimo pranešimas, kuris yra „Neteisingas adresas“, kuris išspausdinamas, jei adresu kažkas negerai. „Ser_address“ suradęs adresą, klientas prisijungs prie serverio. Jei nepavyksta prisijungti, išspausdinama išsami informacija apie klaidą. Funkcija send() perduos pranešimą į serverį, užtikrindama, kad jame nebūtų jokios vėliavėlės.

Norint gauti ir saugoti atsakymą iš serverio, inicijuojamas buferis, pavadintas „buf“, kurio tipas yra „char“. Funkcija read() nuskaito serverio atsakymą į buferį. Galiausiai serverio atsakymas atspausdinamas į konsolę. Galiausiai ryšys uždaromas naudojant close() sakinį, kad būtų nutrauktas lizdas. Tai yra programos išvestis:

Išvada

Lizdų programavimas yra svarbi kompiuterių mokslo tinklo komunikacijos dalis. Tai leidžia kurti programas, galinčias bendrauti tinkle, suteikdamas plačias galimybes nuo paprastos kliento-serverio architektūros iki struktūrizuotų paskirstytų sistemų. Kai programavimo kontekste sukuriamas lizdas, programa turi sukonfigūruoti savo galutinio taško charakteristikas, pvz., protokolus, TCP arba UDP, ir tinklo adresą, pvz., IP adresą ir prievado numerį. Šie lizdai leidžia serveriams siųsti ir gauti duomenis. Šiame straipsnyje pateikiamas praktinis pavyzdys, kaip veikia kliento-serverio modelis programuojant lizdą.