A Linux API könyv. Átfogó útmutató »


A Linux API könyv. Átfogó útmutató »

Jó napot Figyelmébe ajánlom a „Linux API. Átfogó útmutató "(a könyv fordítása A Linux programozási felület). Megrendelhető a kiadó honlapján, illetve a promóciós kód alkalmazása esetén LinuxAPI 30% kedvezményt kapsz.

Egy részlet a könyvből kritikára:

Socket: szerver architektúra

Ebben a fejezetben az iteratív és párhuzamos szerverek tervezésének alapjait tárgyaljuk, valamint egy speciális inetd démont, amely megkönnyíti a szerveroldali internetes alkalmazások létrehozását.

Iterációs és párhuzamos szerverek

Két általános socket alapú hálózati szerver architektúra létezik:

  • iteratív: a szerver egyenként szolgálja ki az ügyfeleket, először feldolgozza az egyik klienstől érkező kérést (vagy több kérést), majd továbblép a következőre;

  • párhuzamos: a szervert több kliens egyidejű kiszolgálására tervezték.

A 44.8. szakaszban már szerepel egy példa egy FIFO-sorokon alapuló iterációs kiszolgálóra.

Az iterációs szerverek általában csak olyan helyzetekben alkalmasak, amikor a kliensek kérései meglehetősen gyorsan feldolgozhatók, mivel minden kliensnek meg kell várnia, amíg az előtte lévő többi klienst kiszolgálják. Ennek a megközelítésnek a gyakori felhasználási esete egyetlen kérés és válasz cseréje az ügyfél és a szerver között.

A párhuzamos szerverek olyan esetekben alkalmasak, amikor egy-egy kérés feldolgozása jelentős időt vesz igénybe, vagy a kliens és a szerver hosszú üzenetváltást folytat. Ebben a fejezetben elsősorban a párhuzamos szerverek tervezésének hagyományos (és legegyszerűbb) módjára koncentrálunk, vagyis minden új klienshez külön gyermekfolyamatot hozunk létre. Egy ilyen folyamat elvégzi az ügyfél kiszolgálásának minden munkáját, amely után véget ér. Mivel ezek a folyamatok egymástól függetlenül működnek, lehetőség van több ügyfél egyidejű kiszolgálására is. A fő szerverfolyamat (szülő) fő feladata, hogy minden új klienshez külön gyermeket hozzon létre (alternatíva a folyamatok helyett a végrehajtási szálakat is létrehozhatja).

A következő szakaszokban az internetes domain socketeken alapuló iteratív és párhuzamos szerverekre fogunk példákat tekinteni. Ez a két szerver az echo szolgáltatás (RFC 862) egyszerűsített változatát valósítja meg, amely visszaküldi a kliens által küldött üzenetek másolatát.

echo iteráció udp szerver

Ebben és a következő részben bemutatjuk az echo szolgáltatás szervereit. A 7-es porton érhető el, és UDP-n és TCP-n is működik (ez a port le van foglalva, ezért az echo szervert rendszergazdai jogosultságokkal kell futtatni).

Az echo UDP szerver folyamatosan olvassa a datagramokat, és visszaküldi azok másolatát a feladónak. Mivel a szervernek egyszerre csak egy üzenetet kell feldolgoznia, itt elegendő egy iteratív architektúra. A kiszolgálók fejlécfájlja az 56.1-XNUMX-es listában látható.

Lista 56.1. Fejléc fájl az id_echo_sv.c és id_echo_cl.c programokhoz

#include "inet_sockets.h" /* Kinyilvánítja a socket függvényeinket */
#include "tlpi_hdr.h"

#define SERVICE "echo" /* UDP szolgáltatás neve */

#define BUF_SIZE 500 /* A datagramok maximális mérete
a kliens és a szerver is olvashatja */
_______________________________________________________________________________ aljzatok/id_echo.h

Az 56.2-XNUMX. lista a szerver megvalósítását mutatja. Érdemes megjegyezni a következő pontokat:

  • a szerver démon módba állításához használjuk a 37.2-es fejezetben található shouldDaemon() függvényt;

  • a program kompaktabbá tételéhez az 55.12 szakaszban kifejlesztett internetes domain socket könyvtárat használjuk;

  • ha a szerver nem tud választ adni a kliensnek, akkor a syslog() hívás segítségével üzenetet ír a naplóba.

Valós alkalmazásban nagy valószínűséggel korlátoznánk az üzenetek naplózásának gyakoriságát a syslog() segítségével. Ez kiküszöbölné annak lehetőségét, hogy egy támadó túlcsorduljon a rendszernaplóban. Ne feledje továbbá, hogy minden syslog() hívás meglehetősen drága, mivel alapértelmezés szerint az fsync() függvényt használja.

Lista 56.2. Egy iterációs szerver, amely megvalósítja az echo UDP szolgáltatást

____________________________________________________________________________sockets/id_echo_sv.c
#beleértve
#include "id_echo.h"
#include "become_daemon.h"

int
main(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, "Nem sikerült létrehozni a szerver socketet (%s)",
strerror(errno));
exit(EXIT_FAILURE);

/* Datagramok fogadása és másolatok visszaküldése a feladóknak */
}
for(;;) {
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)
!= számOlvasás)
syslog(LOG_WARNING, "Hiba a válasz visszhangozásakor %s (%s)",
inetAddressStr((struct sockaddr *) &claddr, len,
addrStr, IS_ADDR_STR_LEN),
strerror(errno));
}
}
____________________________________________________________________________sockets/id_echo_sv.c

Az 56.3-as listában szereplő programot használjuk a szerver tesztelésére. Az 55.12. szakaszban kifejlesztett internetes tartomány socket könyvtárát is használja. A kliensprogram annak a hálózati gazdagépnek a nevét veszi fel, ahol a kiszolgáló található, mint első argumentumot a parancssorban. A kliens belép egy hurokba, ahol a fennmaradó argumentumok mindegyikét külön datagramként küldi el a szervernek, majd válaszként beolvassa és kiadja a szervertől kapott datagramokat.

Lista 56.3. Kliens az echo UDP szolgáltatáshoz

#include "id_echo.h"

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

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

/* A szerver címének kialakítása az első parancssori argumentum alapján */
sfd = inetConnect(argv[1], SZOLGÁLTATÁS, SOCK_DGRAM);
if (sfd == -1)
fatal("Nem sikerült csatlakozni a szerver sockethez");

/* Küldje el a többi argumentumot a szervernek külön datagramként */
for (j = 2; j < argc; j++) {
len = strlen(argv[j]);
if (write(sfd, argv[j], len) != len)
fatal("részleges/sikertelen írás");

numRead = read(sfd, buf, BUF_SIZE);
if (NumRead == -1)
errExit("olvasás");
printf("[%ld bytes] %.*sn", (long) numRead, (int) numRead, buf);
}
exit(EXIT_SIKER);
}
_______________________________________________________________________aljzatok/id_echo_cl.c

A következő példa arra, hogy mit fogunk látni, amikor elindítjuk a kiszolgálót és két klienspéldányt:

$ su // A fenntartott porthoz való kapcsolódáshoz jogosultságok szükségesek
Jelszó:
# ./id_echo_sv // A szerver a háttérbe megy
# kilépés // Adminisztrátori jogok feladása
$ ./id_echo_cl localhost hello world // Ez a kliens két datagrammot küld
[5 bytes] hello // A kliens kiadja a szervertől kapott választ
[5 bájt] világ
$ ./id_echo_cl localhost goodbye // Ez a kliens egy datagrammot küld
[7 bájt] viszlát

Kellemes olvasást kívánok)

Forrás: linux.org.ru