Knjiga “Linux API. Sveobuhvatni vodič"


Knjiga “Linux API. Sveobuhvatni vodič"

Dobar dan Predstavljam vam knjigu “Linux API. Sveobuhvatni vodič" (prijevod knjige Linux programsko sučelje). Može se naručiti na web stranici izdavača, a uz primjenu promotivnog koda LinuxAPI , dobit ćete 30% popusta.

Odlomak iz knjige za referencu:

Utičnice: Arhitektura poslužitelja

U ovom poglavlju raspravljat ćemo o osnovama dizajniranja iterativnih i paralelnih poslužitelja, a također ćemo pogledati poseban demon koji se zove inetd, koji olakšava kreiranje aplikacija internetskog poslužitelja.

Iterativni i paralelni poslužitelji

Postoje dvije uobičajene arhitekture mrežnog poslužitelja temeljene na utičnici:

  • iterativno: poslužitelj poslužuje klijente jednog po jednog, prvo obrađujući zahtjev (ili nekoliko zahtjeva) jednog klijenta, a zatim prelazeći na sljedećeg;

  • paralelno: poslužitelj je dizajniran da služi više klijenata istovremeno.

Primjer iterativnog poslužitelja temeljenog na FIFO redovima već je predstavljen u odjeljku 44.8.

Iterativni poslužitelji obično su prikladni samo u situacijama u kojima se klijentski zahtjevi mogu obraditi prilično brzo, budući da je svaki klijent prisiljen čekati dok svi drugi klijenti ispred njega ne budu usluženi. Uobičajen slučaj korištenja ovog pristupa je razmjena pojedinačnih zahtjeva i odgovora između klijenta i poslužitelja.

Paralelni poslužitelji prikladni su u slučajevima kada je za obradu svakog zahtjeva potrebno dosta vremena ili kada klijent i poslužitelj razmjenjuju duge poruke. U ovom poglavlju ćemo se uglavnom usredotočiti na tradicionalni (i najjednostavniji) način projektiranja paralelnih poslužitelja, a to je stvaranje zasebnog procesa djeteta za svakog novog klijenta. Ovaj proces obavlja sav posao za posluživanje klijenta i zatim završava. Budući da svaki od ovih procesa radi neovisno, moguće je opsluživati ​​više klijenata istovremeno. Glavni zadatak glavnog poslužiteljskog procesa (roditelj) je kreiranje zasebnog djeteta za svakog novog klijenta (alternativno, niti procesa se mogu kreirati umjesto procesa).

U sljedećim odjeljcima pogledat ćemo primjere iterativnih i paralelnih socket poslužitelja internetske domene. Ova dva poslužitelja implementiraju pojednostavljenu verziju usluge echo (RFC 862), koja vraća kopiju bilo koje poruke koju mu pošalje klijent.

Iterativni odjek UDP poslužitelja

U ovom i sljedećem odjeljku predstavit ćemo poslužitelje za uslugu echo. Dostupan je na priključku broj 7 i radi preko UDP-a i TCP-a (ovaj je priključak rezerviran, pa se stoga echo poslužitelj mora pokrenuti s administratorskim ovlastima).

Echo UDP poslužitelj kontinuirano čita datagrame i vraća njihove kopije pošiljatelju. Budući da poslužitelj treba obraditi samo jednu po jednu poruku, dovoljna je iterativna arhitektura. Datoteka zaglavlja za poslužitelje prikazana je u ispisu 56.1.

Listing 56.1. Datoteka zaglavlja za programe id_echo_sv.c i id_echo_cl.c

#include "inet_sockets.h" /* Deklariše naše funkcije soketa */
#include "tlpi_hdr.h"

#define SERVICE "echo" /* naziv UDP usluge */

#define BUF_SIZE 500 /* Maksimalna veličina datagrama koji
mogu čitati klijent i poslužitelj */
_________________________________________________________________________________sockets/id_echo.h

Ispis 56.2 prikazuje implementaciju poslužitelja. Sljedeće točke su vrijedne pažnje:

  • za postavljanje poslužitelja u demonski način rada koristimo funkciju becomeDaemon() iz odjeljka 37.2;

  • kako bismo program učinili kompaktnijim, koristimo biblioteku za rad s utičnicama internetske domene, razvijenu u odjeljku 55.12;

  • ako poslužitelj ne može vratiti odgovor klijentu, zapisuje poruku u zapisnik pomoću syslog() poziva.

U stvarnoj aplikaciji vjerojatno bismo nametnuli neka ograničenja na učestalost zapisivanja poruka pomoću syslog(). To bi eliminiralo mogućnost da napadač prepuni zapisnik sustava. Osim toga, nemojte zaboraviti da je svaki poziv syslog() prilično skup, budući da koristi fsync() prema zadanim postavkama.

Listing 56.2. Iteracijski poslužitelj koji implementira UDP echo uslugu

_________________________________________________________________sockets/id_echo_sv.c
#uključi
#include "id_echo.h"
#include "become_daemon.h"

int
main(int argc, char *argv[])
{
int sfd;
ssize_t numRead;
socklen_t len;
struct sockaddr_storage claddr;
char buf[BUF_SIZE];
char addrStr[IS_ADDR_STR_LEN];

if (postatiDaemon(0) == -1)
errIzlaz("postatiDaemon");

sfd = inetBind(SERVICE, SOCK_DGRAM, NULL);
if (sfd == -1) {
syslog(LOG_ERR, "Nije moguće stvoriti poslužiteljsku utičnicu (%s)",
strerror(errno));
izlaz(EXIT_FAILURE);

/* Primanje datagrama i vraćanje njihovih kopija pošiljateljima */
}
za (;;) {
len = sizeof(struct sockaddr_storage);
numRead = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *) &claddr, &len);

if (numRead == -1)
errExit("recvfrom");
if (sendto(sfd, buf, numRead, 0, (struct sockaddr *) &claddr, len)
!= numRead)
syslog(LOG_WARNING, "Pogreška eho odgovora na %s (%s)",
inetAddressStr((struct sockaddr *) &claddr, len,
addStr, IS_ADDR_STR_LEN),
strerror(errno));
}
}
_________________________________________________________________sockets/id_echo_sv.c

Za testiranje rada poslužitelja koristimo program iz listinga 56.3. Također koristi biblioteku za rad s utičnicama internetske domene, razvijenu u odjeljku 55.12. Kao prvi argument naredbenog retka klijentski program uzima naziv mrežnog čvora na kojem se nalazi poslužitelj. Klijent ulazi u petlju gdje šalje svaki od preostalih argumenata poslužitelju kao zasebne datagrame, a zatim čita i ispisuje datagrame koje prima od poslužitelja kao odgovor.

Listing 56.3. Klijent za UDP echo uslugu

#include "id_echo.h"

int
main(int argc, char *argv[])
{
int sfd, j;
veličina_t dužina;
ssize_t numRead;
char buf[BUF_SIZE];

if (argc < 2 || strcmp(argv[1], "--help") == 0)
usageErr("%s host msg…n", argv[0]);

/* Formirajte adresu poslužitelja na temelju prvog argumenta naredbenog retka */
sfd = inetConnect(argv[1], SERVIS, SOCK_DGRAM);
ako (sfd == -1)
fatal("Nije moguće spojiti se na poslužiteljsku utičnicu");

/* Pošalji preostale argumente poslužitelju u obliku zasebnih datagrama */
za (j = 2; j < argc; j++) {
len = strlen(argv[j]);
if (write(sfd, argv[j], len) != len)
fatal("djelomično/neuspješno pisanje");

numRead = read(sfd, buf, BUF_SIZE);
if (numRead == -1)
errExit("čitaj");
printf("[%ld bytes] %.*sn", (long) numRead, (int) numRead, buf);
}
izlaz(IZLAZAK_USPJEH);
}
_________________________________________________________________sockets/id_echo_cl.c

Ispod je primjer onoga što ćemo vidjeti kada pokrenemo server i dvije klijentske instance:

$su // Privilegije su potrebne za vezanje na rezervirani port
Lozinka:
# ./id_echo_sv // Poslužitelj prelazi u pozadinski način rada
# izlaz // Odricanje administratorskih prava
$ ./id_echo_cl localhost hello world // Ovaj klijent šalje dva datagrama
[5 bajtova] pozdrav // Klijent prikazuje odgovor primljen od poslužitelja
[5 bajtova] svijet
$ ./id_echo_cl localhost zbogom // Ovaj klijent šalje jedan datagram
[7 bajtova] zbogom

Želim vam ugodno čitanje)

Izvor: linux.org.ru