Grāmata "Linux API. Visaptveroša rokasgrāmata »


Grāmata "Linux API. Visaptveroša rokasgrāmata »

Labdien Jūsu uzmanībai piedāvāju grāmatu “Linux API. Visaptverošs ceļvedis" (grāmatas tulkojums Linux programmēšanas interfeiss). To var pasūtīt izdevēja vietnē un, ja lietojat reklāmas kodu LinuxAPI , saņemsi 30% atlaidi.

Izvilkums no grāmatas uzziņai:

Sockets: servera arhitektūra

Šajā nodaļā mēs apspriedīsim iteratīvo un paralēlo serveru projektēšanas pamatus, kā arī apskatīsim īpašu dēmonu ar nosaukumu inetd, kas atvieglo interneta serveru lietojumprogrammu izveidi.

Iteratīvie un paralēlie serveri

Pastāv divas izplatītas uz ligzdām balstītas tīkla serveru arhitektūras:

  • iteratīvs: serveris apkalpo klientus pa vienam, vispirms apstrādājot pieprasījumu (vai vairākus pieprasījumus) no viena klienta un pēc tam pārejot uz nākamo;

  • paralēli: serveris ir paredzēts, lai vienlaikus apkalpotu vairākus klientus.

Iteratīva servera piemērs, kura pamatā ir FIFO rindas, jau tika parādīts sadaļā 44.8.

Iteratīvie serveri parasti ir piemēroti tikai situācijās, kad klientu pieprasījumus var apstrādāt diezgan ātri, jo katrs klients ir spiests gaidīt, līdz tiks apkalpoti citi klienti, kas atrodas tā priekšā. Izplatīts šīs pieejas lietošanas gadījums ir atsevišķu pieprasījumu un atbilžu apmaiņa starp klientu un serveri.

Paralēli serveri ir piemēroti gadījumos, kad katra pieprasījuma apstrāde prasa ievērojamu laiku vai ja klients un serveris iesaistās ilgstošā ziņojumu apmaiņā. Šajā nodaļā mēs galvenokārt koncentrēsimies uz tradicionālo (un vienkāršāko) paralēlo serveru projektēšanas veidu, proti, katram jaunam klientam izveidot atsevišķu atvasināto procesu. Šis process veic visu darbu, lai apkalpotu klientu, un pēc tam beidzas. Tā kā katrs no šiem procesiem darbojas neatkarīgi, ir iespējams apkalpot vairākus klientus vienlaicīgi. Galvenā servera procesa (parent) galvenais uzdevums ir katram jaunam klientam izveidot atsevišķu bērnu (alternatīvi procesu vietā var izveidot izpildes pavedienus).

Nākamajās sadaļās mēs apskatīsim iteratīvo un paralēlo interneta domēna ligzdas serveru piemērus. Šie divi serveri ievieš vienkāršotu atbalss pakalpojuma versiju (RFC 862), kas atgriež jebkura klienta nosūtītā ziņojuma kopiju.

Iteratīva UDP servera atbalss

Šajā un nākamajā sadaļā mēs iepazīstināsim ar atbalss pakalpojuma serveriem. Tas ir pieejams portā ar numuru 7 un darbojas gan UDP, gan TCP (šis ports ir rezervēts, un tāpēc echo serveris ir jādarbina ar administratora privilēģijām).

Echo UDP serveris nepārtraukti nolasa datagrammas un atdod to kopijas sūtītājam. Tā kā serverim vienlaikus jāapstrādā tikai viens ziņojums, pietiks ar iteratīvu arhitektūru. Serveru galvenes fails ir parādīts sarakstā 56.1.

Saraksts 56.1. Galvenes fails programmām id_echo_sv.c un id_echo_cl.c

#include "inet_sockets.h" /* Deklarē mūsu ligzdas funkcijas */
#include "tlpi_hdr.h"

#define SERVICE "echo" /* UDP pakalpojuma nosaukums */

#define BUF_SIZE 500 /* Maksimālais datugrammu izmērs, kas
var lasīt klients un serveris */
_______________________________________________________________________________sockets/id_echo.h

Saraksts 56.2 parāda servera ieviešanu. Ir vērts pievērst uzmanību šādiem punktiem:

  • lai serveri pārslēgtu dēmona režīmā, mēs izmantojam 37.2. sadaļas funkciju beginDaemon();

  • lai programma būtu kompaktāka, izmantojam bibliotēku darbam ar interneta domēna ligzdām, kas izstrādāta sadaļā 55.12;

  • ja serveris nevar atgriezt atbildi klientam, tas ieraksta ziņojumu žurnālā, izmantojot syslog() izsaukumu.

Reālā lietojumprogrammā mēs, iespējams, noteiktu ierobežojumu ziņojumu reģistrēšanas biežumam, izmantojot syslog (). Tas novērstu iespēju, ka uzbrucējs pārpildīs sistēmas žurnālu. Turklāt neaizmirstiet, ka katrs syslog() izsaukums ir diezgan dārgs, jo tas pēc noklusējuma izmanto fsync().

Saraksts 56.2. Iterācijas serveris, kas ievieš UDP atbalss pakalpojumu

_______________________________________________________________________ligzdas/id_echo_sv.c
#iekļauts
#include "id_echo.h"
#include "become_daemon.h"

int
galvenais (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("becomeDaemon");

sfd = inetBind(SERVISS, SOCK_DGRAM, NULL);
if (sfd == -1) {
syslog(LOG_ERR, "Nevarēja izveidot servera ligzdu (%s)",
strerror(errno));
iziet(EXIT_FAILURE);

/* Saņemt datagrammas un nosūtīt to kopijas sūtītājiem */
}
priekš (;;) {
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, "Kļūda, atbildot uz %s (%s)",
inetAddressStr((struct sockaddr *) &claddr, len,
addrStr, IS_ADDR_STR_LEN),
strerror(errno));
}
}
_______________________________________________________________________ligzdas/id_echo_sv.c

Lai pārbaudītu servera darbību, mēs izmantojam programmu no saraksta 56.3. Tā izmanto arī bibliotēku darbam ar interneta domēna ligzdām, kas izstrādāta sadaļā 55.12. Kā pirmo komandrindas argumentu klienta programma izmanto tā tīkla mezgla nosaukumu, kurā atrodas serveris. Klients ievada cilpu, kurā tas katru no atlikušajiem argumentiem nosūta serverim kā atsevišķas datagrammas un pēc tam nolasa un izdrukā no servera saņemtās datagrammas kā atbildi.

Saraksts 56.3. UDP atbalss pakalpojuma klients

#include "id_echo.h"

int
galvenais (int argc, char *argv[])
{
int sfd, j;
izmērs_t len;
ssize_t numRead;
char buf [BUF_SIZE];

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

/* Izveidojiet servera adresi, pamatojoties uz pirmo komandrindas argumentu */
sfd = inetConnect(argv[1], PAKALPOJUMS, SOCK_DGRAM);
ja (sfd == -1)
fatal ("Nevarēja izveidot savienojumu ar servera ligzdu");

/* Nosūtiet atlikušos argumentus serverim atsevišķu datagrammu veidā */
ja (j = 2; j < argc; j++) {
len = strlen(argv[j]);
if (rakstīt(sfd, argv[j], len) != len)
fatāls ("daļēja/neizdevusies rakstīšana");

numRead = lasīt(sfd, buf, BUF_SIZE);
if (numRead == -1)
errExit("lasīt");
printf("[%ld baiti] %.*sn", (garš) numRead, (int) numRead, buf);
}
iziet (EXIT_SUCCESS);
}
_______________________________________________________________________ligzdas/id_echo_cl.c

Tālāk ir sniegts piemērs tam, ko mēs redzēsim, palaižot serveri un divus klienta gadījumus:

$su // Lai izveidotu savienojumu ar rezervētu portu, ir nepieciešamas privilēģijas
parole:
# ./id_echo_sv // Serveris pāriet fona režīmā
# iziet // Atteikties no administratora tiesībām
$ ./id_echo_cl localhost hello world // Šis klients nosūta divas datagrammas
[5 baiti] sveiki // Klients parāda no servera saņemto atbildi
[5 baiti] pasaule
$ ./id_echo_cl localhost goodbye // Šis klients nosūta vienu datagrammu
[7 baiti] ardievu

Es novēlu jums patīkamu lasīšanu)

Avots: linux.org.ru