Kniha „Linux API. Komplexní průvodce"


Kniha „Linux API. Komplexní průvodce"

Dobré odpoledne Předkládám vaší pozornosti knihu „Linux API. Komplexní průvodce“ (překlad knihy Linuxové programovací rozhraní). Lze si jej objednat na webu vydavatele, a pokud použijete propagační kód LinuxAPI , získáte slevu 30 %.

Pro referenci úryvek z knihy:

Sokety: Serverová architektura

V této kapitole probereme základy navrhování iterativních a paralelních serverů a také se podíváme na speciálního démona zvaného inetd, který usnadňuje vytváření aplikací internetového serveru.

Iterativní a paralelní servery

Existují dvě běžné architektury síťových serverů založené na soketech:

  • iterativní: server obsluhuje klienty jednoho po druhém, nejprve zpracuje požadavek (nebo několik požadavků) od jednoho klienta a poté přejde k dalšímu;

  • paralelní: server je navržen tak, aby obsluhoval více klientů současně.

Příklad iterativního serveru založeného na frontách FIFO byl již uveden v sekci 44.8.

Iterativní servery jsou obvykle vhodné pouze v situacích, kdy mohou být požadavky klientů zpracovány poměrně rychle, protože každý klient je nucen čekat, až budou obslouženi ostatní klienti před ním. Běžným případem použití tohoto přístupu je výměna jednotlivých požadavků a odpovědí mezi klientem a serverem.

Paralelní servery jsou vhodné v případech, kdy zpracování každého požadavku trvá značné množství času nebo kde se klient a server zapojují do dlouhé výměny zpráv. V této kapitole se zaměříme především na tradiční (a nejjednodušší) způsob navrhování paralelních serverů, kterým je vytvoření samostatného podřízeného procesu pro každého nového klienta. Tento proces provede veškerou práci, aby sloužil klientovi, a poté skončí. Protože každý z těchto procesů funguje nezávisle, je možné obsluhovat více klientů současně. Hlavním úkolem hlavního procesu serveru (rodiče) je vytvořit samostatného potomka pro každého nového klienta (alternativně lze místo procesů vytvořit vlákna provádění).

V následujících částech se podíváme na příklady iterativních a paralelních soketových serverů internetové domény. Tyto dva servery implementují zjednodušenou verzi služby echo (RFC 862), která vrací kopii jakékoli zprávy odeslané na něj klientem.

Iterativní echo serveru UDP

V této a další části představíme servery pro službu echo. Je k dispozici na portu číslo 7 a funguje přes UDP i TCP (tento port je vyhrazený, a proto musí být echo server spuštěn s právy správce).

Echo UDP server nepřetržitě čte datagramy a vrací jejich kopie odesílateli. Vzhledem k tomu, že server potřebuje zpracovat pouze jednu zprávu najednou, postačí iterativní architektura. Soubor hlavičky pro servery je uveden ve výpisu 56.1.

Výpis 56.1. Soubor záhlaví pro programy id_echo_sv.c a id_echo_cl.c

#include "inet_sockets.h" /* Deklaruje naše funkce soketu */
#include "tlpi_hdr.h"

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

#define BUF_SIZE 500 /* Maximální velikost datagramů, která
lze číst klientem a serverem */
______________________________________________________________________zásuvky/id_echo.h

Výpis 56.2 ukazuje implementaci serveru. Za zmínku stojí následující body:

  • k uvedení serveru do režimu démona použijeme funkci beginDaemon() ze sekce 37.2;

  • aby byl program kompaktnější, používáme knihovnu pro práci s internetovými doménovými sockety, vyvinutou v sekci 55.12;

  • pokud server nemůže vrátit odpověď klientovi, zapíše zprávu do protokolu pomocí volání syslog().

Ve skutečné aplikaci bychom pravděpodobně zavedli určitý limit na frekvenci protokolování zpráv pomocí syslog(). Tím by se eliminovala možnost, že by útočník přeplnil systémový protokol. Kromě toho nezapomeňte, že každé volání syslog() je poměrně drahé, protože standardně používá fsync().

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

___________________________________________________________________zásuvky/id_echo_sv.c
#zahrnout
#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 (becomeDaemon(0) == -1)
errExit("stane seDaemon");

sfd = inetBind(SERVICE, SOCK_DGRAM, NULL);
if (sfd == -1) {
syslog(LOG_ERR, "Nelze vytvořit serverový soket (%s)",
strerror(errno));
exit(EXIT_FAILURE);

/* Přijímat datagramy a vracet jejich kopie odesílatelům */
}
pro (;;) {
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 při opakování odpovědi na %s (%s)",
inetAddressStr((struct sockaddr *) &claddr, len,
addrStr, IS_ADDR_STR_LEN),
strerror(errno));
}
}
___________________________________________________________________zásuvky/id_echo_sv.c

K otestování provozu serveru používáme program z výpisu 56.3. Používá také knihovnu pro práci se sokety internetových domén, vyvinutou v sekci 55.12. Jako první argument příkazového řádku přebírá klientský program název síťového uzlu, na kterém je server umístěn. Klient vstoupí do smyčky, kde odešle každý ze zbývajících argumentů na server jako jednotlivé datagramy a poté načte a vytiskne datagramy, které obdrží ze serveru jako odpověď.

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

#include "id_echo.h"

int
main(int argc, char *argv[])
{
int sfd, j;
size_t len;
ssize_t numRead;
char buf[BUF_SIZE];

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

/* Vytvořte adresu serveru na základě prvního argumentu příkazového řádku */
sfd = inetConnect(argv[1], SERVICE, SOCK_DGRAM);
if (sfd == -1)
fatal("Nelze se připojit k soketu serveru");

/* Odešle zbývající argumenty na server ve formě samostatných datagramů */
for (j = 2; j < argc; j++) {
len = strlen(argv[j]);
if (write(sfd, argv[j], len) != len)
fatal("částečný/neúspěšný zápis");

numRead = read(sfd, buf, BUF_SIZE);
if (numRead == -1)
errExit("číst");
printf("[%ld bajtů] %.*sn", (dlouhé) numRead, (int) numRead, buf);
}
exit(EXIT_SUCCESS);
}
___________________________________________________________________zásuvky/id_echo_cl.c

Níže je uveden příklad toho, co uvidíme při spuštění serveru a dvou klientských instancí:

$su // Pro vazbu na vyhrazený port jsou vyžadována oprávnění
heslo:
# ./id_echo_sv // Server přejde do režimu na pozadí
# exit // Vzdát se práv správce
$ ./id_echo_cl localhost hello world // Tento klient posílá dva datagramy
[5 bajtů] ahoj // Klient zobrazí odpověď přijatou ze serveru
[5 bajtů] svět
$ ./id_echo_cl localhost sbohem // Tento klient odešle jeden datagram
[7 bajtů] sbohem

Přeji příjemné čtení)

Zdroj: linux.org.ru