Boken "Linux API. Omfattende guide»


Boken "Linux API. Omfattende guide»

God ettermiddag Jeg presenterer for din oppmerksomhet boken "Linux API. En omfattende guide" (oversettelse av boken Linux programmeringsgrensesnitt). Den kan bestilles på utgiverens nettsted, og hvis du bruker kampanjekoden LinuxAPI , får du 30 % rabatt.

Utdrag fra boken for referanse:

Sockets: Serverarkitektur

I dette kapittelet vil vi diskutere det grunnleggende om utforming av iterative og parallelle servere, og også se på en spesiell daemon kalt inetd, som gjør det enklere å lage Internett-serverapplikasjoner.

Iterative og parallelle servere

Det er to vanlige socket-baserte nettverksserverarkitekturer:

  • iterativ: serveren betjener klienter én om gangen, behandler først en forespørsel (eller flere forespørsler) fra én klient og går deretter videre til den neste;

  • parallell: serveren er designet for å betjene flere klienter samtidig.

Et eksempel på en iterativ server basert på FIFO-køer ble allerede presentert i avsnitt 44.8.

Iterative servere er vanligvis bare egnet i situasjoner der klientforespørsler kan behandles ganske raskt, siden hver klient er tvunget til å vente til andre klienter foran den har blitt servert. Et vanlig bruksområde for denne tilnærmingen er utveksling av enkeltforespørsler og svar mellom en klient og server.

Parallelle servere er egnet i tilfeller der hver forespørsel tar betydelig tid å behandle, eller hvor klienten og serveren deltar i lange meldingsutvekslinger. I dette kapittelet vil vi hovedsakelig fokusere på den tradisjonelle (og enkleste) måten å designe parallelle servere på, som er å lage en egen underordnet prosess for hver ny klient. Denne prosessen utfører alt arbeidet for å betjene klienten og avsluttes deretter. Fordi hver av disse prosessene fungerer uavhengig, er det mulig å betjene flere klienter samtidig. Hovedoppgaven til hovedserverprosessen (foreldre) er å lage et eget underordnet for hver nye klient (alternativt kan utføringstråder opprettes i stedet for prosesser).

I de følgende avsnittene vil vi se på eksempler på iterative og parallelle internettdomene-socket-servere. Disse to serverne implementerer en forenklet versjon av ekkotjenesten (RFC 862), som returnerer en kopi av en melding sendt til den av en klient.

Iterativt UDP-serverekko

I denne og neste delen vil vi introdusere serverne for ekkotjenesten. Den er tilgjengelig på port nummer 7 og fungerer over både UDP og TCP (denne porten er reservert, og derfor må ekkoserveren kjøres med administratorrettigheter).

Echo UDP-serveren leser datagrammer kontinuerlig og returnerer kopier av dem til avsenderen. Siden serveren bare trenger å behandle én melding om gangen, vil en iterativ arkitektur være tilstrekkelig. Overskriftsfilen for serverne vises i oppføring 56.1.

Oppføring 56.1. Overskriftsfil for programmene id_echo_sv.c og id_echo_cl.c

#include "inet_sockets.h" /* Erklærer funksjonene til kontakten vår */
#include "tlpi_hdr.h"

#define SERVICE "echo" /* UDP-tjenestenavn */

#define BUF_SIZE 500 /* Maksimal størrelse på datagrammer som
kan leses av klient og server */
__________________________________________________________________sockets/id_echo.h

Oppføring 56.2 viser serverimplementeringen. Følgende punkter er verdt å merke seg:

  • for å sette serveren i daemon-modus, bruker vi funksjonen becomeDaemon() fra seksjon 37.2;

  • for å gjøre programmet mer kompakt bruker vi biblioteket for å jobbe med internettdomene-sockets, utviklet i avsnitt 55.12;

  • hvis serveren ikke kan returnere et svar til klienten, skriver den en melding til loggen ved å bruke syslog()-kallet.

I en ekte applikasjon vil vi sannsynligvis pålegge en viss grense for frekvensen av loggingsmeldinger ved å bruke syslog(). Dette vil eliminere muligheten for at en angriper flyter over systemloggen. I tillegg, ikke glem at hvert kall til syslog() er ganske dyrt, siden det bruker fsync() som standard.

Oppføring 56.2. Iterasjonsserver som implementerer UDP-ekkotjenesten

_________________________________________________________________sockets/id_echo_sv.c
#inkludere
#include "id_echo.h"
#include "become_daemon.h"

int
main(int argc, char *argv[])
{
int sfd;
ssize_t numRead;
socklen_t len;
struct sockaddr_lagring claddr;
røye buff[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, "Kunne ikke opprette serversocket (%s)",
strerror(feilno));
exit(EXIT_FAILURE);

/* Motta datagrammer og returnere kopier av dem til avsenderne */
}
for (;;) {
len = sizeof(struct sockaddr_lagring);
numRead = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *) &claddr, &len);

if (antallLes == -1)
errExit("recvfrom");
if (sendto(sfd, buf, numRead, 0, (struct sockaddr *) &claddr, len)
!= numLest)
syslog(LOG_WARNING, "Feil ved ekko av respons til %s (%s)",
inetAddressStr((struct sockaddr *) &claddr, len,
addrStr, IS_ADDR_STR_LEN),
strerror(feilno));
}
}
_________________________________________________________________sockets/id_echo_sv.c

For å teste serverens drift bruker vi programmet fra Listing 56.3. Den bruker også biblioteket for å jobbe med domenekontakter for Internett, utviklet i avsnitt 55.12. Som det første kommandolinjeargumentet tar klientprogrammet navnet på nettverksnoden som serveren er plassert på. Klienten går inn i en sløyfe der den sender hvert av de gjenværende argumentene til serveren som separate datagrammer, og deretter leser og skriver ut datagrammene den mottar fra serveren som svar.

Oppføring 56.3. Klient for UDP ekkotjeneste

#include "id_echo.h"

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

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

/* Form serveradressen basert på det første kommandolinjeargumentet */
sfd = inetConnect(argv[1], SERVICE, SOCK_DGRAM);
if (sfd == -1)
fatal("Kunne ikke koble til serversocket");

/* Send de resterende argumentene til serveren i form av separate datagrammer */
for (j = 2; j < argc; j++) {
len = strlen(argv[j]);
if (skriv(sfd, argv[j], len) != len)
fatal("delvis/mislykket skriving");

numRead = read(sfd, buf, BUF_SIZE);
if (antallLes == -1)
errExit("les");
printf("[%ld bytes] %.*sn", (lang) numRead, (int) numRead, buf);
}
exit(EXIT_SUCCESS);
}
_________________________________________________________________sockets/id_echo_cl.c

Nedenfor er et eksempel på hva vi vil se når du kjører serveren og to klientforekomster:

$su // Privilegier kreves for å binde seg til en reservert port
Passord:
# ./id_echo_sv // Server går inn i bakgrunnsmodus
# exit // Gi opp administratorrettigheter
$ ./id_echo_cl localhost hello world // Denne klienten sender to datagrammer
[5 bytes] hello // Klienten viser svaret mottatt fra serveren
[5 bytes] verden
$ ./id_echo_cl localhost farvel // Denne klienten sender ett datagram
[7 bytes] farvel

Jeg ønsker deg en hyggelig lesning)

Kilde: linux.org.ru