Knyga „Linux API. Išsamus vadovas »


Knyga „Linux API. Išsamus vadovas »

Laba diena Atkreipiu jūsų dėmesį į knygą „Linux API. Išsamus vadovas "(knygos vertimas Linux programavimo sąsaja). Jį galima užsisakyti leidėjo svetainėje ir pritaikius reklamos kredito kodą LinuxAPI gausite 30% nuolaidą.

Ištrauka iš knygos peržiūrai:

Lizdai: serverio architektūra

Šiame skyriuje aptarsime iteracinių ir lygiagrečių serverių projektavimo pagrindus, taip pat specialų inetd demoną, kuris palengvina serverio interneto programų kūrimą.

Iteracijos ir lygiagrečiai serveriai

Yra dvi įprastos lizdais pagrįstos tinklo serverių architektūros:

  • iteracinis: serveris aptarnauja klientus po vieną, pirmiausia apdorodamas vieno kliento užklausą (arba kelias užklausas), o tada pereidamas prie kito;

  • lygiagrečiai: serveris skirtas aptarnauti kelis klientus vienu metu.

44.8 skyriuje jau pateiktas iteracijos serverio, pagrįsto FIFO eilėmis, pavyzdys.

Iteracijos serveriai dažniausiai tinka tik tais atvejais, kai klientų užklausas galima apdoroti gana greitai, nes kiekvienas klientas turi palaukti, kol bus aptarnauti visi kiti prieš jį esantys klientai. Įprastas šio metodo naudojimo atvejis yra keistis atskiromis užklausomis ir atsakymais tarp kliento ir serverio.

Lygiagretūs serveriai tinka tais atvejais, kai kiekvienos užklausos apdorojimas užima daug laiko arba klientas ir serveris ilgai keičiasi žinutėmis. Šiame skyriuje daugiausia dėmesio skirsime tradiciniam (ir lengviausiam) lygiagrečių serverių projektavimo būdui, ty kiekvienam naujam klientui sukurti atskirą antrinį procesą. Toks procesas atlieka visą kliento aptarnavimo darbą, po kurio baigiasi. Kadangi kiekvienas iš šių procesų veikia savarankiškai, vienu metu galima aptarnauti kelis klientus. Pagrindinė pagrindinio serverio proceso (pagrindinio) užduotis yra sukurti atskirą antrinį pobūdį kiekvienam naujam klientui (arba vietoj procesų galite sukurti vykdymo gijas).

Tolesniuose skyriuose apžvelgsime iteracinių ir lygiagrečių serverių, pagrįstų interneto domeno lizdais, pavyzdžius. Šie du serveriai įgyvendina supaprastintą echo paslaugos versiją (RFC 862), kuri grąžina bet kokio kliento jam išsiųsto pranešimo kopiją.

echo iteration udp serveris

Šiame ir kitame skyrelyje pristatysime echo paslaugos serverius. Jis prieinamas prie 7 prievado ir veikia tiek per UDP, tiek per TCP (šis prievadas yra rezervuotas, todėl echo serveris turi būti paleistas su administratoriaus teisėmis).

Echo UDP serveris nuolat skaito datagramas ir grąžina jų kopiją siuntėjui. Kadangi serveriui vienu metu reikia apdoroti tik vieną pranešimą, čia užteks kartotinės architektūros. Serverių antraštės failas rodomas 56.1-XNUMX sąraše.

Sąrašas 56.1. Programų id_echo_sv.c ir id_echo_cl.c antraštės failas

#include "inet_sockets.h" /* Deklaruoja mūsų lizdų funkcijas */
#include "tlpi_hdr.h"

#define SERVICE "echo" /* UDP paslaugos pavadinimas */

#define BUF_SIZE 500 /* Maksimalus datagramų dydis
gali skaityti klientas ir serveris */
______________________________________________________________________________ lizdai/id_echo.h

Sąrašas 56.2-XNUMX rodo serverio įgyvendinimą. Verta atkreipti dėmesį į šiuos dalykus:

  • norėdami įjungti serverį į demono režimą, naudojame 37.2 skyriaus funkciją taptiDaemon();

  • kad programa būtų kompaktiškesnė, naudojame 55.12 skyriuje sukurtą interneto domeno socket biblioteką;

  • jei serveris negali atsakyti klientui, jis rašo pranešimą į žurnalą naudodamas syslog() iškvietimą.

Tikroje programoje greičiausiai nustatysime tam tikrą limitą pranešimų registravimo dažnumui naudojant syslog(). Tai pašalins galimybę, kad užpuolikas perpildytų sistemos žurnalą. Be to, atminkite, kad kiekvienas syslog() skambutis yra gana brangus, nes pagal numatytuosius nustatymus jis naudoja fsync().

Sąrašas 56.2. Iteracijos serveris, įgyvendinantis echo UDP paslaugą

___________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
#įtraukti
#include "id_echo.h"
#include "become_daemon.h"

int
pagrindinis (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 (becomeDaemon(0) == -1)
errExit("becomeDaemon");

sfd = inetBind(SERVICE, SOCK_DGRAM, NULL);
if (sfd == -1) {
syslog(LOG_ERR, "Nepavyko sukurti serverio lizdo (%s)",
strerror(errno));
išeiti (EXIT_FAILURE);

/* Gauti datagramas ir grąžinti kopijas siuntėjams */
}
dėl(;;) {
len = dydisof(struct sockaddr_storage);
numRead = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *) &claddr, &len);

jei (skaitomas skaičius == -1)
errExit("recvfrom");
if (sendto(sfd, buf, numRead, 0, (struct sockaddr *) &claddr, len)
!=NumRead)
syslog(LOG_WARNING, "Klaida atkartojant atsakymą į %s (%s)",
inetAddressStr((struct sockaddr *) &claddr, len,
addrStr, IS_ADDR_STR_LEN),
strerror(errno));
}
}
___________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

Mes naudojame 56.3 sąraše esančią programą serveriui išbandyti. Ji taip pat naudoja interneto domeno lizdų biblioteką, sukurtą 55.12 skyriuje. Kliento programa naudoja tinklo pagrindinio kompiuterio, kuriame yra serveris, pavadinimą kaip pirmąjį argumentą komandinėje eilutėje. Klientas įeina į ciklą, kuriame siunčia visus likusius argumentus į serverį kaip atskiras datagramas, o tada nuskaito ir išveda iš serverio gautas datagramas atsakydamas.

Sąrašas 56.3. Echo UDP paslaugos klientas

#include "id_echo.h"

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

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

/* Suformuokite serverio adresą pagal pirmąjį komandinės eilutės argumentą */
sfd = inetConnect(argv[1], PASLAUGA, SOCK_DGRAM);
jei (sfd == -1)
fatal ("Nepavyko prisijungti prie serverio lizdo");

/* Siųsti likusius argumentus į serverį kaip atskiras datagramas */
už (j = 2; j < argc; j++) {
len = strlen(argv[j]);
if (write (sfd, argv[j], len) != len)
fatal("dalinis/nepavyko rašyti");

numRead = skaityti (sfd, buf, BUF_SIZE);
jei (skaitomas skaičius == -1)
errExit("skaityti");
printf("[%ld baitų] %.*sn", (ilgas) numRead, (int) numRead, buf);
}
išeiti (EXIT_SUCCESS);
}
___________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________echo_cl.c

Toliau pateikiamas pavyzdys, ką matysime, kai paleisime serverį ir du kliento egzempliorius:

$ su // Norint susieti su rezervuotu prievadu, reikia privilegijų
Slaptažodis:
# ./id_echo_sv // Serveris pereina į foną
# išeiti // Atsisakyti administratoriaus teisių
$ ./id_echo_cl localhost hello world // Šis klientas siunčia dvi datagramas
[5 baitai] labas // Klientas išveda atsakymą, gautą iš serverio
[5 baitai] pasaulis
$ ./id_echo_cl localhost goodbye // Šis klientas siunčia vieną datagramą
[7 baitai] atsisveikink

Linkiu malonaus skaitymo)

Šaltinis: linux.org.ru