Boek "Linux API. Folsleine gids"


Boek "Linux API. Folsleine gids"

Goeiemiddei Ik presintearje jo oandacht it boek "Linux API. In wiidweidige gids" (oersetting fan it boek De Linux Programming Interface). It kin besteld wurde op 'e webside fan' e útjouwer, en as jo de promoasjekoade tapasse LinuxAPI , jo krije 30% koarting.

Úttreksel út it boek foar referinsje:

Sockets: Server Architecture

Yn dit haadstik sille wy beprate de basis fan it ûntwerpen fan iterative en parallelle tsjinners, en ek sjogge op in spesjale daemon neamd inetd, dat makket it makliker te meitsjen ynternet tsjinner applikaasjes.

Iterative en parallelle tsjinners

D'r binne twa mienskiplike socket-basearre netwurkserverarsjitektueren:

  • iteratyf: de tsjinner tsjinnet kliïnten ien foar ien, ferwurket earst in fersyk (of ferskate oanfragen) fan ien klant en giet dan troch nei de folgjende;

  • parallel: de tsjinner is ûntworpen om meardere kliïnten tagelyk te tsjinjen.

In foarbyld fan in iterative tsjinner basearre op FIFO-wachtrijen waard al presintearre yn paragraaf 44.8.

Iterative tsjinners binne meastentiids allinnich geskikt yn situaasjes dêr't kliïnt fersiken kinne wurde ferwurke frij fluch, sûnt eltse klant wurdt twongen om te wachtsjen oant alle oare kliïnten foar him binne tsjinne. In mienskiplik gebrûk foar dizze oanpak is de útwikseling fan inkele oanfragen en antwurden tusken in kliïnt en tsjinner.

Parallelle tsjinners binne geskikt yn gefallen dêr't elk fersyk duorret in wichtige hoemannichte tiid om te ferwurkjen, of dêr't de kliïnt en tsjinner dwaande hâlde mei lange berjocht útwikseling. Yn dit haadstik sille wy benammen rjochtsje op 'e tradisjonele (en ienfâldichste) manier fan it ûntwerpen fan parallelle tsjinners, dat is it meitsjen fan in apart bernproses foar elke nije kliïnt. Dit proses fiert al it wurk om de klant te tsjinjen en einiget dan. Om't elk fan dizze prosessen ûnôfhinklik wurket, is it mooglik om meardere kliïnten tagelyk te tsjinjen. De haadtaak fan it haadtsjinnerproses (âlder) is om in apart bern te meitsjen foar elke nije kliïnt (as alternatyf kinne threads fan útfiering oanmakke wurde ynstee fan prosessen).

Yn 'e folgjende seksjes sille wy nei foarbylden sjen fan iterative en parallelle socketservers foar ynternetdomeinen. Dizze twa tsjinners ymplementearje in ferienfâldige ferzje fan 'e echo-tsjinst (RFC 862), dy't in kopy werombringt fan elk berjocht dat troch in kliïnt stjoerd is.

Iterative UDP-tsjinner echo

Yn dizze en de folgjende seksje sille wy de servers foar de echo-tsjinst yntrodusearje. It is beskikber op poarte nûmer 7 en wurket oer sawol UDP as TCP (dizze poarte is reservearre, en dêrom moat de echo-tsjinner wurde útfierd mei administratorrjochten).

De echo UDP-tsjinner lêst kontinu datagrammen en jout kopyen derfan werom nei de stjoerder. Om't de tsjinner mar ien berjocht tagelyk hoecht te ferwurkjen, sil in iterative arsjitektuer genôch wêze. De koptekst foar de servers wurdt werjûn yn Listing 56.1.

Listing 56.1. Kopteksttriem foar programma's id_echo_sv.c en id_echo_cl.c

#include "inet_sockets.h" /* Ferklearret ús socketfunksjes */
#include "tlpi_hdr.h"

#define SERVICE "echo" /* UDP tsjinst namme */

#define BUF_SIZE 500 /* Maksimum grutte fan datagrammen dy't
kin lêzen wurde troch client en server */
__________________________________________________________________sockets/id_echo.h

Listing 56.2 toant de tsjinner ymplemintaasje. De folgjende punten binne it wurdich op te merken:

  • om de tsjinner yn daemon modus te setten, brûke wy de funksje wurdenDaemon () fan seksje 37.2;

  • om it programma kompakter te meitsjen, brûke wy de bibleteek om te wurkjen mei ynternetdomein-sockets, ûntwikkele yn paragraaf 55.12;

  • as de tsjinner kin net werom in antwurd op de klant, it skriuwt in berjocht nei it log mei help fan de syslog () call.

Yn in echte applikaasje soene wy ​​​​wierskynlik wat limyt oplizze op 'e frekwinsje fan it oanmelden fan berjochten mei syslog (). Dit soe de mooglikheid eliminearje dat in oanfaller it systeemlogboek oerstreamt. Dêrneist ferjit net dat elke oprop nei syslog () frij djoer is, om't it standert fsync () brûkt.

Listing 56.2. Iteraasjetsjinner dy't de UDP-echo-tsjinst ymplementearret

__________________________________________________sockets/id_echo_sv.c
#ynklusyf
#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 adrStr[IS_ADDR_STR_LEN];

if (becomeDaemon(0) == -1)
errExit("becomeDaemon");

sfd = inetBind(SERVICE, SOCK_DGRAM, NULL);
if (sfd == -1) {
syslog(LOG_ERR, "Koe de tsjinner socket (%s) net oanmeitsje",
strerror(errno));
exit(EXIT_FAILURE);

/* Untfang datagrammen en stjoer kopyen derfan werom nei de ôfstjoerders */
}
foar (;;) {
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, "Flater by echo antwurd op %s (%s)",
inetAddressStr((struct sockaddr *) &claddr, len,
addrStr, IS_ADDR_STR_LEN),
strerror(errno));
}
}
__________________________________________________sockets/id_echo_sv.c

Om de wurking fan de tsjinner te testen, brûke wy it programma fan Listing 56.3. It brûkt ek de bibleteek foar it wurkjen mei ynternetdomein-sockets, ûntwikkele yn seksje 55.12. As it earste kommando-rigelargumint nimt it kliïntprogramma de namme fan it netwurkknooppunt dêr't de tsjinner leit. De kliïnt komt in lus yn wêr't it elk fan 'e oerbleaune arguminten nei de tsjinner stjoert as aparte datagrammen, en dan lêst en printet de datagrammen dy't it ûntfangt fan 'e tsjinner as antwurd.

Listing 56.3. Kliïnt foar UDP echo tsjinst

#include "id_echo.h"

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

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

/* Formearje it tsjinneradres basearre op it earste kommandorigelargument */
sfd = inetConnect(argv[1], SERVICE, SOCK_DGRAM);
if (sfd == -1)
fatal ("Koe gjin ferbining meitsje mei tsjinner socket");

/* Stjoer de oerbleaune arguminten nei de tsjinner yn 'e foarm fan aparte datagrammen */
foar (j = 2; j < argc; j++) {
len = strlen(argv[j]);
if (skriuw(sfd, argv[j], len) != len)
fatal("partiel/mislearre skriuwen");

numRead = read(sfd, buf, BUF_SIZE);
if (numRead == -1)
errExit("lêze");
printf("[%ld bytes] %.*sn", (long) numRead, (int) numRead, buf);
}
ôfslute (EXIT_SUCCESS);
}
__________________________________________________sockets/id_echo_cl.c

Hjirûnder is in foarbyld fan wat wy sille sjen by it útfieren fan de server en twa client-eksimplaren:

$su // Privileges binne ferplichte om te binen oan in reservearre haven
Wachtwurd:
# ./id_echo_sv // Tsjinner giet yn eftergrûnmodus
# ôfslute // Jou behearderrjochten op
$ ./id_echo_cl localhost hello world // Dizze klant stjoert twa datagrammen
[5 bytes] hallo // De client toant it antwurd ûntfongen fan de tsjinner
[5 bytes] wrâld
$ ./id_echo_cl localhost oant sjen // Dizze klant stjoert ien datagram
[7 bytes] oant sjen

Ik winskje jo in noflik lêzen)

Boarne: linux.org.ru