Kniha „Linux API. Komplexný sprievodca »


Kniha „Linux API. Komplexný sprievodca »

Dobrý deň Do pozornosti dávam knihu „Linux API. Komplexný sprievodca“ (preklad knihy Linuxové programovacie rozhranie). Dá sa objednať na stránke vydavateľstva a ak uplatníte promo kód LinuxAPI získate 30% zľavu.

Úryvok z knihy na recenziu:

Sockety: serverová architektúra

V tejto kapitole sa budeme zaoberať základmi navrhovania iteračných a paralelných serverov, ako aj špeciálneho démona inetd, ktorý uľahčuje vytváranie internetových aplikácií na strane servera.

Iteračné a paralelné servery

Existujú dve bežné architektúry sieťových serverov založené na zásuvkách:

  • iteratívny: server obsluhuje klientov jedného po druhom, pričom najskôr spracuje požiadavku (alebo niekoľko požiadaviek) jedného klienta a potom prejde k ďalšiemu;

  • paralelný: server je navrhnutý tak, aby obsluhoval viacerých klientov súčasne.

Časť 44.8 už poskytla príklad iteračného servera založeného na frontoch FIFO.

Iteračné servery sú zvyčajne vhodné iba v situáciách, kde môžu byť požiadavky klientov spracované pomerne rýchlo, pretože každý klient musí čakať, kým nebudú obsluhovaní ostatní klienti pred ním. Bežným prípadom použitia tohto prístupu je výmena jednotlivých požiadaviek a odpovedí medzi klientom a serverom.

Paralelné servery sú vhodné v prípadoch, keď spracovanie každej požiadavky trvá značné množstvo času alebo ak medzi klientom a serverom prebieha dlhá výmena správ. V tejto kapitole sa zameriame hlavne na tradičný (a najjednoduchší) spôsob navrhovania paralelných serverov, ktorým je vytvorenie samostatného podriadeného procesu pre každého nového klienta. Takýto proces robí všetku prácu pri obsluhe klienta, po ktorej končí. Keďže každý z týchto procesov funguje samostatne, je možné obsluhovať viacerých klientov súčasne. Hlavnou úlohou hlavného serverového procesu (rodiča) je vytvoriť samostatného potomka pre každého nového klienta (alternatívne namiesto procesov môžete vytvoriť vlákna vykonávania).

V nasledujúcich častiach sa pozrieme na príklady iteračných a paralelných serverov založených na zásuvkách internetovej domény. Tieto dva servery implementujú zjednodušenú verziu služby echo (RFC 862), ktorá vracia kópiu akejkoľvek správy odoslanej klientom.

echo iteration udp server

V tejto a nasledujúcej časti predstavíme servery pre službu echo. Je dostupný na porte číslo 7 a funguje cez UDP aj TCP (tento port je vyhradený, a preto musí byť echo server spustený s oprávneniami správcu).

Echo UDP server neustále číta datagramy a vracia ich kópiu odosielateľovi. Keďže server potrebuje naraz spracovať iba jednu správu, postačí tu iteratívna architektúra. Súbor hlavičky pre servery je uvedený vo výpise 56.1-XNUMX.

Výpis 56.1. Hlavičkový súbor pre programy id_echo_sv.c a id_echo_cl.c

#include "inet_sockets.h" /* Deklaruje naše funkcie soketov */
#include "tlpi_hdr.h"

#define SERVICE "echo" /* Názov služby UDP */

#define BUF_SIZE 500 /* Maximálna veľkosť datagramov, ktorá
môžu byť čítané klientom a serverom */
_________________________________________________________________________ zásuvky/id_echo.h

Výpis 56.2-XNUMX ukazuje implementáciu servera. Stojí za zmienku nasledujúce body:

  • na uvedenie servera do režimu démona použijeme funkciu getsDaemon() zo sekcie 37.2;

  • aby bol program kompaktnejší, používame knižnicu zásuviek internetovej domény vyvinutú v sekcii 55.12;

  • ak server nemôže vrátiť odpoveď klientovi, zapíše správu do protokolu pomocou volania syslog().

V reálnej aplikácii by sme s najväčšou pravdepodobnosťou stanovili určitý limit na frekvenciu protokolovania správ pomocou syslog(). Tým by sa eliminovala možnosť, že by útočník preplnil systémový denník. Majte tiež na pamäti, že každé volanie syslog() je dosť drahé, pretože štandardne používa fsync().

Výpis 56.2. Iteračný server, ktorý implementuje službu echo UDP

___________________________________________________________________zásuvky/id_echo_sv.c
#include
#include "id_echo.h"
#include "become_daemon.h"

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

if (stane saDaemonom(0) == -1)
errExit("stane saDaemon");

sfd = inetBind(SERVICE, SOCK_DGRAM, NULL);
if (sfd == -1) {
syslog(LOG_ERR, "Nepodarilo sa vytvoriť soket servera (%s)",
strerror(errno));
exit(EXIT_FAILURE);

/* Prijímanie datagramov a vrátenie kópií odosielateľom */
}
pre(;;) {
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, "Chyba pri odozve na %s (%s)",
inetAddressStr((struct sockaddr *) &claddr, len,
addrStr, IS_ADDR_STR_LEN),
strerror(errno));
}
}
___________________________________________________________________zásuvky/id_echo_sv.c

Na testovanie servera používame program zo zoznamu 56.3. Používa tiež knižnicu soketov internetovej domény vyvinutú v časti 55.12. Klientsky program berie ako prvý argument na príkazovom riadku názov sieťového hostiteľa, na ktorom sa nachádza server. Klient vstúpi do slučky, v ktorej odošle každý zo zostávajúcich argumentov na server ako samostatné datagramy a potom načíta a odošle datagramy prijaté zo servera ako odpoveď.

Výpis 56.3. Klient pre službu echo UDP

#include "id_echo.h"

int
main(int argc, char *argv[])
{
int sfd,j;
size_tlen;
ssize_t numRead;
charbuf[BUF_SIZE];

if (argc < 2 || strcmp(argv[1], "--help") == 0)
useErr("%s hostiteľská správa…n", argv[0]);

/* Vytvorte adresu servera na základe prvého argumentu príkazového riadka */
sfd = inetConnect(argv[1], SLUŽBA, SOCK_DGRAM);
if (sfd == -1)
fatal("Nepodarilo sa pripojiť k soketu servera");

/* Pošlite zvyšok argumentov na server ako samostatné datagramy */
for (j = 2; j < argc; j++) {
len = strlen(argv[j]);
if (write(sfd, argv[j], len) != len)
fatal("čiastočný/neúspešný zápis");

numRead = read(sfd, buf, BUF_SIZE);
if (numRead == -1)
errExit("prečítať");
printf("[%ld bajtov] %.*sn", (dlhá) numRead, (int) numRead, buf);
}
exit(EXIT_SUCCESS);
}
___________________________________________________________________zásuvky/id_echo_cl.c

Nasleduje príklad toho, čo uvidíme, keď spustíme server a dve inštancie klienta:

$ su // Vyžaduje privilégiá na viazanie na vyhradený port
heslo:
# ./id_echo_sv // Server prejde do pozadia
# exit // Vzdať sa práv správcu
$ ./id_echo_cl localhost hello world // Tento klient posiela dva datagramy
[5 bajtov] ahoj // Klient vypíše odpoveď prijatú zo servera
[5 bajtov] svet
$ ./id_echo_cl localhost zbohom // Tento klient odošle jeden datagram
[7 bajtov] dovidenia

Prajem príjemné čítanie)

Zdroj: linux.org.ru