Китеп "Linux API. Комплекстүү колдонмо"


Китеп "Linux API. Комплекстүү колдонмо"

Кутмандуу күнүң менен! Мен сиздердин назарыңыздарга “Linux API. Комплекстүү колдонмо» (китептин котормосу Linux программалоо интерфейси). Бул жарыялоочунун сайтында заказ кылынышы мүмкүн, жана сиз жарнамалык кодду колдонсоңуз болот LinuxAPI , сиз 30% арзандатуу аласыз.

Маалымат үчүн китептен үзүндү:

Sockets: Server Architecture

Бул бөлүмдө биз итеративдик жана параллелдүү серверлерди долбоорлоонун негиздерин талкуулайбыз, ошондой эле интернет сервердик тиркемелерди түзүүнү жеңилдеткен inetd деп аталган атайын демонду карайбыз.

Итеративдик жана параллелдүү серверлер

Эки жалпы розеткага негизделген тармак серверинин архитектурасы бар:

  • кайталануучу: сервер кардарларды бирден тейлейт, адегенде бир кардардын суроо-талабын (же бир нече суроону) иштеп чыгып, андан кийин экинчисине өтөт;

  • параллелдүү: сервер бир эле учурда бир нече кардарларды тейлөө үчүн иштелип чыккан.

FIFO кезектерине негизделген кайталануучу сервердин мисалы 44.8-бөлүмдө берилген.

Итеративдик серверлер, адатта, кардарлардын суроо-талаптары тез арада иштетиле турган жагдайларда гана ылайыктуу, анткени ар бир кардар анын алдында турган башка кардарлар тейленгенге чейин күтүүгө аргасыз болот. Бул ыкманы колдонуунун кеңири таралган учуру кардар менен сервердин ортосундагы бирдиктүү суроо-талаптарды жана жоопторду алмашуу болуп саналат.

Параллель серверлер ар бир суроо-талапты иштетүү үчүн бир топ убакытты талап кылган учурларда же кардар менен сервер узакка созулган билдирүү алмашууда ылайыктуу. Бул бөлүмдө биз негизинен параллелдүү серверлерди долбоорлоонун салттуу (жана эң жөнөкөй) ыкмасына токтолобуз, бул ар бир жаңы кардар үчүн өзүнчө бала процессин түзүү. Бул процесс кардарды тейлөө үчүн бардык иштерди аткарат жана андан кийин бүтөт. Бул процесстердин ар бири өз алдынча иштегендиктен, бир эле учурда бир нече кардарларды тейлөөгө болот. Негизги сервер процессинин (ата-эне) негизги милдети ар бир жаңы кардар үчүн өзүнчө бала түзүү (же болбосо процесстердин ордуна аткаруу жиптерин түзсө болот).

Кийинки бөлүмдөрдө биз кайталануучу жана параллелдүү интернет домендик розетка серверлеринин мисалдарын карап чыгабыз. Бул эки сервер жаңырык кызматынын (RFC 862) жөнөкөйлөштүрүлгөн версиясын ишке ашырат, ал кардар ага жөнөтүлгөн ар кандай билдирүүнүн көчүрмөсүн кайтарат.

Итеративдик UDP серверинин жаңырыгы

Ушул жана кийинки бөлүмдө биз echo кызматы үчүн серверлерди тааныштырабыз. Ал №7 портто жеткиликтүү жана UDP жана TCP экөө тең иштейт (бул порт сакталган, ошондуктан жаңырык сервери администратор артыкчылыктары менен иштетилиши керек).

Echo UDP сервери тынымсыз датаграммаларды окуп, алардын көчүрмөлөрүн жөнөтүүчүгө кайтарып берет. Сервер бир эле учурда бир билдирүүнү иштетиши керек болгондуктан, кайталануучу архитектура жетиштүү болот. Серверлердин баш файлы 56.1 листингде көрсөтүлгөн.

Листинг 56.1. id_echo_sv.c жана id_echo_cl.c программалары үчүн баш файл

#include "inet_sockets.h" /* Биздин розетка функцияларыбызды жарыялайт */
#include "tlpi_hdr.h"

#define SERVICE "echo" /* UDP кызматынын аталышы */

#define BUF_SIZE 500 /* Датаграммалардын максималдуу өлчөмү
кардар жана сервер тарабынан окулат */
_________________________________________________________________розеткалар/id_echo.h

Листинг 56.2 сервердин ишке ашырылышын көрсөтөт. Төмөнкү пункттарды белгилей кетүү керек:

  • серверди демон режимине коюу үчүн, биз 37.2 бөлүмүндөгү becomeDaemon() функциясын колдонобуз;

  • программаны компакттуу кылуу үчүн биз 55.12 бөлүмүндө иштелип чыккан Интернет домендик розеткалары менен иштөө үчүн китепкананы колдонобуз;

  • эгерде сервер кардарга жооп кайтара албаса, анда syslog() чалуу аркылуу журналга билдирүү жазат.

Чыныгы тиркемеде биз syslog() аркылуу билдирүүлөрдү жазуу жыштыгына кандайдыр бир чектөө киргизишибиз мүмкүн. Бул чабуулчунун система журналын басып алуу мүмкүнчүлүгүн жок кылат. Кошумчалай кетсек, syslog()га ар бир чалуу абдан кымбат экенин унутпаңыз, анткени ал демейки боюнча fsync() колдонот.

Листинг 56.2. UDP echo кызматын ишке ашырган итерация сервери

_________________________________________________________________розеткалар/id_echo_sv.c
#киргизүү
#include "id_echo.h"
#include "become_daemon.h"

Int
негизги(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(SERVICE, SOCK_DGRAM, NULL);
if (sfd == -1) {
syslog(LOG_ERR, "Сервер розеткасын түзө алган жок (%s)",
strerror(ката));
exit(EXIT_FAILURE);

/* Датаграммаларды алуу жана алардын көчүрмөлөрүн жөнөтүүчүлөргө кайтаруу */
}
үчүн (;;) {
len = sizeof(struct sockaddr_storage);
numRead = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *) &claddr, &len);

эгерде (numRead == -1)
errExit("recvfrom");
if (sendto(sfd, buf, numRead, 0, (struct sockaddr *) &claddr, len)
!= numRead)
syslog(LOG_WARNING, "%s (%s) жоопту жаңыртуудагы ката",
inetAddressStr((struct sockaddr *) &claddr, len,
addrStr, IS_ADDR_STR_LEN),
strerror(ката));
}
}
_________________________________________________________________розеткалар/id_echo_sv.c

Сервердин иштешин текшерүү үчүн биз Listing 56.3 программасын колдонобуз. Ал ошондой эле 55.12 бөлүмүндө иштелип чыккан Интернет домендик розеткалары менен иштөө үчүн китепкананы колдонот. Биринчи буйрук сабынын аргументи катары кардар программасы сервер жайгашкан тармак түйүнүнүн атын алат. Кардар циклге кирет, ал жерде калган аргументтердин ар бирин серверге өзүнчө датаграммалар катары жөнөтөт, андан кийин жооп катары серверден алган датаграммаларды окуп, басып чыгарат.

Листинг 56.3. UDP эхо кызматы үчүн кардар

#include "id_echo.h"

Int
негизги(int argc, char *argv[])
{
int sfd, j;
size_t len;
ssize_t numRead;
char buf[BUF_SIZE];

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

/* Биринчи буйрук сабынын аргументинин негизинде сервердин дарегин түзүңүз */
sfd = inetConnect(argv[1], SERVICE, SOCK_DGRAM);
эгерде (sfd == -1)
fatal("Сервер розеткасына туташа алган жок");

/* Калган аргументтерди серверге өзүнчө датаграммалар түрүндө жөнөтүңүз */
үчүн (j = 2; j < argc; j++) {
len = strlen(argv[j]);
if (write(sfd, argv[j], len) != len)
fatal("жарым-жартылай/жазылбай калган");

numRead = окуу(sfd, buf, BUF_SIZE);
эгерде (numRead == -1)
errExit("окуу");
printf("[%ld bytes] %.*sn", (uzun) numRead, (int) numRead, buf);
}
exit(EXIT_SUCCESS);
}
_________________________________________________________________розеткалар/id_echo_cl.c

Төмөндө серверди жана эки кардар инстанциясын иштеткенде биз көрө турган мисал:

$su // Артыкчылыктар сакталган портко туташуу үчүн талап кылынат
Купуя сөз:
# ./id_echo_sv // Сервер фондо режимге өтөт
# чыгуу // Администратордук укуктардан баш тартуу
$ ./id_echo_cl localhost hello world // Бул кардар эки датаграмма жөнөтөт
[5 байт] салам // Кардар серверден алынган жоопту көрсөтөт
[5 байт] дүйнө
$ ./id_echo_cl localhost кош // Бул кардар бир датаграмманы жөнөтөт
[7 байт] кош

Мен сизге жагымдуу окуу каалайм)

Source: linux.org.ru