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