Soketové programování v C++

Soketove Programovani V C



Programování zásuvek se stalo důležitým předmětem v oblasti počítačových sítí. Zahrnuje navázání spojení mezi dvěma uzly, serverem a klientem, aby spolu mohli komunikovat bez jakéhokoli přerušení. Server funguje jako posluchač v komunikačním kanálu a naslouchá klientovi na konkrétním portu na IP adrese. Na druhé straně klient vystupuje v komunikačním kanálu jako komunikátor. Klient kontaktuje server, aby vytvořil spojení a navázal kontakt se serverem. Tento článek si klade za cíl poskytnout komplexního a podrobného průvodce programováním soketů v C++, který zahrnuje základy, uvádí praktické příklady a poskytuje podrobné vysvětlení kódu.

Vytvoření modelu klient-server

Programování soketů je proces, který vytváří komunikační kanál mezi serverem a klientem pomocí soketů. V následujícím příkladu kódu klient zahájí kontakt se serverem a server je nastaven tak, aby přijímal připojení klienta. Pojďme pochopit segmenty kódu serveru a klienta tím, že předvedeme jejich jádro práce v rámci síťové komunikace. Následuje kód na straně serveru. Podívejme se nejprve na kód a poté jej podrobně vysvětlíme, bod po bodu.

1. Strana serveru







Kód pro serverovou stranu modelu je uveden níže. Podívejme se, co se děje v kódu:



#include
#include
#include
#include

použitím jmenný prostor std ;

#define PORT 8080
#define MAX_BUF_SIZE 1024

int hlavní ( ) {
int ser_socket, cli_socket ;
strukturovat sockaddr_in ser_address, cli_address ;
char buf [ MAX_BUF_SIZE ] = { 0 } ;

-li ( ( ser_socket = zásuvka ( AF_INET, SOCK_STREAM, 0 ) ) == - 1 ) {
chyba ( 'Chyba při vytváření zásuvky' ) ;
výstup ( EXIT_FAILURE ) ;
}

ser_address. sin_family = OF_INET ;
ser_address. sin_addr . s_addr = INADDR_ANY ;
ser_address. sin_port = htonů ( PŘÍSTAV ) ;

-li ( svázat ( be_socket, ( strukturovat sockaddr * ) & ser_address, velikost ( ser_address ) ) == - 1 ) {
chyba ( 'Selhání ve vazbě' ) ;
výstup ( EXIT_FAILURE ) ;
}

-li ( poslouchat ( be_socket, 3 ) == - 1 ) {
chyba ( 'Nepodařilo se poslouchat' ) ;
výstup ( EXIT_FAILURE ) ;
}

cout << 'Server naslouchající na portu' << PŘÍSTAV << '... \n ' ;

socklen_t cli_address_len = velikost ( cli_address ) ;
-li ( ( cli_socket = akceptovat ( be_socket, ( strukturovat sockaddr * ) & cli_address, & cli_address_len ) ) == - 1 ) {
chyba ( 'Nepodařilo se přijmout' ) ;
výstup ( EXIT_FAILURE ) ;
}

číst ( cli_socket, buf, MAX_BUF_SIZE ) ;
cout << 'Sdělení klienta je:' << buf << endl ;

poslat ( cli_socket, 'Zpráva serveru' , strlen ( 'Zpráva serveru' ) , 0 ) ;

zavřít ( cli_socket ) ;
zavřít ( ser_socket ) ;

vrátit se 0 ;
}

Uvedený příklad je kód programu C++ na straně serveru. Tento kód funguje pro jednoduchý TCP server, který naslouchá připojení na jednom konkrétním portu. Po úspěšném vytvoření připojení server obdrží zprávu odeslanou z klienta. Poté jej vytiskne na konzoli a odešle klientovi zprávu s odpovědí. Pojďme pochopit každý řádek kódu.



Program začíná zahrnutím knihoven: „iostream“ pro standardní definice vstupu/výstupu, „cstring“ pro funkce zpracování řetězců, „unistd.h“ pro přístup k API operačního systému POSIX a „arpa/inet.h“ pro provádět operace na internetu. Příkaz „#define PORT 8080“ znamená, že definuje číslo portu 8080, na kterém bude server naslouchat. „#define MAX_BUF_SIZE 1024“ znamená maximální velikost vyrovnávací paměti pro příchozí data, která je 1024.





V hlavní funkci jsou inicializovány dvě proměnné, „ser_socket“ a „cli_socket“, které reprezentují server i klienta. Další tři proměnné, kterými jsou „sockaddr_in“, „ser_address“ a „cli_address“ typu „struct“, jsou inicializovány jako struktury adres pro server a klienta. Poté se inicializuje vyrovnávací paměť s názvem „buf“, která ukládá data pocházející od klienta.

Funkce socket() v podmínce „if“ vytvoří nový soket TCP. AF_INET označuje IPv4, SOCK_STREAM představuje na připojení orientovaný a spolehlivý soket TCP, poslední argument, kterým je 0, slouží k výběru výchozího protokolu TCP, INADDR_ANY přijímá připojení na libovolné IP adrese a htons (PORT) převádí číslo portu z pořadí bajtů hostitele k pořadí bajtů sítě.



Protože je vše správně definováno, dalším krokem je nastavit server jako lister na daném portu a přijímat připojení na libovolném síťovém rozhraní. Soket je dán informací v „ser_address“ metodou bind(). Vytiskneme chybu a proces ukončíme, pokud vazba selže. Funkce accept() otevře nový soket pro spojení s klientem, zatímco funkce listen() nařídí serveru, aby čekal na příchozí spojení. Pokud funkce accept() selže, vytiskne se chybová zpráva a funkce se ukončí.

Dále server přečte zprávu klienta s funkcí read() do „buf“ vyrovnávací paměti a poté ji vytiskne do konzole. Funkci send() používá server k odeslání zprávy jako odpovědi klientovi. Nakonec pomocí close() server uzavře soket klienta a ukončí program, takže všechna připojení jsou řádně uzavřena a neexistuje žádná pravděpodobnost úniku dat.

2. Strana klienta

Nyní se podívejme, co se děje v klientském modelu:

#include
#include
#include
#include

#define PORT 8080
#define SERVER_IP '127.0.0.1'

int hlavní ( ) {
int cli_socket ;
strukturovat sockaddr_in ser_address ;
konst char * zpráva = 'Klient posílá pozdravy!' ;

-li ( ( cli_socket = zásuvka ( AF_INET, SOCK_STREAM, 0 ) ) == - 1 ) {
chyba ( 'Chyba při vytváření socketu' ) ;
výstup ( EXIT_FAILURE ) ;
}

ser_address. sin_family = OF_INET ;
ser_address. sin_port = htonů ( PŘÍSTAV ) ;

-li ( inet_pton ( AF_INET, SERVER_IP, & ser_address. sin_addr ) <= 0 ) {
chyba ( 'Špatná adresa' ) ;
výstup ( EXIT_FAILURE ) ;
}

-li ( připojit ( cli_socket, ( strukturovat sockaddr * ) & ser_address, velikost ( ser_address ) ) == - 1 ) {
chyba ( 'Selhání připojení' ) ;
výstup ( EXIT_FAILURE ) ;
}
poslat ( cli_socket, mesg, strlen ( zpráva ) , 0 ) ;

char buf [ 1024 ] = { 0 } ;
číst ( cli_socket, buf, velikost ( buf ) ) ;
std :: cout << 'Odpověď serveru:' << buf << std :: endl ;

zavřít ( cli_socket ) ;
vrátit se 0 ;
}

Podívejme se na každý řádek kódu, abychom pochopili, jak program funguje.

Stejné čtyři knihovny – iostream, cstring, unistd.h a arpa/inet.h – jsou také zahrnuty na straně klienta. Číslo portu je také definováno spolu s IP adresou místního hostitele 127.0.0.1. Je dána zpráva, která má být doručena na server. Klient a server musí navázat spojení v následujícím kroku:

„if ((client_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1);“ vytvoří soket pro IPv4 s typem streamu a výchozím protokolem TCP. Pokud se funkci socket() nepodaří navázat spojení a program ukončí, vypíše perror() podrobnosti o chybě.

Adresa „server_address.sin_port = htons(PORT);“ nastavuje číslo portu po převodu na síťové pořadí bajtů. Poté je zde uvedena další chybová zpráva, která je „Špatná adresa“, která se vytiskne, pokud je s adresou něco v nepořádku. Vyhledáním adresy v „serv_address“ se klient připojí k serveru. Pokud se připojení nezdaří, vytisknou se podrobnosti o chybě. Funkce send() přenese zprávu na server a zajistí, že nebude obsahovat žádný příznak.

Pro příjem a uložení odpovědi ze serveru se inicializuje vyrovnávací paměť s názvem „buf“ typu „char“. Funkce read() čte odpověď serveru do vyrovnávací paměti. Nakonec se odpověď serveru vytiskne do konzole. Nakonec se spojení uzavře pomocí příkazu close() k ukončení soketu. Následuje výstup programu:

Závěr

Soketové programování je důležitou součástí síťové komunikace v informatice. Umožňuje vývoj aplikací, které mohou komunikovat po síti, což umožňuje širokou škálu možností od jednoduchých architektur klient-server až po strukturované distribuované systémy. Když je soket vytvořen v kontextu programování, program musí nakonfigurovat charakteristiky jeho koncového bodu, jako jsou protokoly, TCP nebo UDP, a síťovou adresu, jako je adresa IP a číslo portu. Tyto sokety umožňují serverům odesílat a přijímat data. Tento článek ukazuje praktický příklad toho, jak funguje model klient-server v programování soketů.