Linux API кітабы. Толық нұсқаулық»


Linux API кітабы. Толық нұсқаулық»

Қайырлы күн! Мен сіздердің назарларыңызға «Linux API. Кешенді нұсқаулық» (кітаптың аудармасы Linux бағдарламалау интерфейсі). Оны баспагердің веб-сайтында тапсырыс беруге болады, және егер сіз промокодты қолдансаңыз LinuxAPI 30% жеңілдік аласыз.

Шолу үшін кітаптан үзінді:

Розеткалар: сервер архитектурасы

Бұл тарауда біз итеративті және параллель серверлерді жобалау негіздерін, сонымен қатар серверлік интернет қосымшаларын құруды жеңілдететін арнайы inetd демонын талқылаймыз.

Итерация және параллель серверлер

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

  • итеративті: сервер клиенттерге бір-бірден қызмет көрсетеді, алдымен бір клиенттің сұранысын (немесе бірнеше сұрауларын) өңдейді, содан кейін келесісіне өтеді;

  • параллель: сервер бір уақытта бірнеше клиентке қызмет көрсетуге арналған.

44.8 бөлімінде FIFO кезектеріне негізделген итерация серверінің мысалы берілген.

Итерация серверлері әдетте клиенттік сұрауларды жеткілікті жылдам өңдеуге болатын жағдайларда ғана жарамды, өйткені әрбір клиент алдында тұрған кез келген басқа клиенттерге қызмет көрсетілгенше күту керек. Бұл тәсіл үшін жалпы қолдану жағдайы клиент пен сервер арасында жалғыз сұраулар мен жауаптарды алмасу болып табылады.

Параллельді серверлер әрбір сұранысты өңдеуге көп уақытты қажет ететін немесе клиент пен сервер ұзақ хабарлама алмасуы болған жағдайда қолайлы. Бұл тарауда біз негізінен параллельді серверлерді жобалаудың дәстүрлі (және ең оңай) әдісіне, яғни әрбір жаңа клиент үшін бөлек еншілес процесті құруға тоқталамыз. Мұндай процесс клиентке қызмет көрсетудің барлық жұмысын орындайды, содан кейін ол аяқталады. Бұл процестердің әрқайсысы дербес жұмыс істейтіндіктен, бір уақытта бірнеше клиентке қызмет көрсетуге болады. Негізгі сервер процесінің (ата-аналық) негізгі міндеті - әрбір жаңа клиент үшін жеке еншілес құру (балама түрде, процестердің орнына орындау ағындарын жасауға болады).

Келесі бөлімдерде біз интернет-домен ұяларына негізделген итеративті және параллель серверлердің мысалдарын қарастырамыз. Бұл екі сервер клиент жіберген кез келген хабарламаның көшірмесін қайтаратын жаңғырық қызметінің (RFC 862) жеңілдетілген нұсқасын жүзеге асырады.

echo итерациясы udp сервері

Осы және келесі бөлімде біз echo қызметіне арналған серверлерді таныстырамыз. Ол №7 портта қол жетімді және UDP және TCP арқылы жұмыс істейді (бұл порт сақталған, сондықтан жаңғырық сервері әкімші артықшылықтарымен іске қосылуы керек).

Echo UDP сервері үнемі датаграммаларды оқиды және олардың көшірмесін жіберушіге қайтарады. Сервер бір уақытта тек бір хабарламаны өңдеуі қажет болғандықтан, мұнда итеративті архитектура жеткілікті болады. Серверлерге арналған тақырып файлы 56.1-XNUMX тізімде көрсетілген.

Листинг 56.1. id_echo_sv.c және id_echo_cl.c бағдарламаларына арналған тақырып файлы

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

#define SERVICE "echo" /* UDP қызметінің атауы */

#define BUF_SIZE 500 /* Датаграммалардың ең үлкен өлшемі
клиент пен сервер оқи алады */
______________________________________________________________________ розеткалар/id_echo.h

56.2-XNUMX листинг серверді іске асыруды көрсетеді. Келесі тармақтарды атап өткен жөн:

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

  • бағдарламаны ықшамдау үшін біз 55.12 бөлімінде әзірленген интернет-домендік ұяшықтар кітапханасын қолданамыз;

  • егер сервер клиентке жауап қайтара алмаса, ол syslog() шақыруы арқылы журналға хабарлама жазады.

Нақты қолданбада біз syslog() арқылы хабарларды тіркеу жиілігіне белгілі бір шектеу қояр едік. Бұл шабуылдаушының жүйе журналынан асып кету мүмкіндігін жояды. Сондай-ақ, әрбір syslog() қоңырауы өте қымбат екенін есте сақтаңыз, себебі ол әдепкі бойынша fsync() пайдаланады.

Листинг 56.2. echo UDP қызметін жүзеге асыратын итерация сервері

_________________________________________________________________розеткалар/id_echo_sv.c
#қосу
#қосуға "id_echo.h"
#қосу "become_daemon.h"

INT
негізгі(int argc, char *argv[])
{
int sfd;
ssize_t numRead;
socklen_tlen;
struct sockaddr_storage claddr;
charbuf[BUF_SIZE];
char addrStr[IS_ADDR_STR_LEN];

егер (Daemon болу(0) == -1)
errExit("BecomeDaemon");

sfd = inetBind(SERVICE, SOCK_DGRAM, NULL);
егер (sfd == -1) {
syslog(LOG_ERR, "Сервер ұясын (%s) жасау мүмкін болмады",
strerror(қате));
шығу(EXIT_FAILURE);

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

егер (numRead == -1)
errExit("recvfrom");
егер (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

Біз серверді тексеру үшін 56.3 листингіндегі бағдарламаны қолданамыз. Ол сондай-ақ 55.12 бөлімінде әзірленген Интернет доменінің ұяшықтары кітапханасын пайдаланады. Клиенттік бағдарлама пәрмен жолындағы бірінші аргумент ретінде сервер орналасқан желі хостының атын алады. Клиент циклге енеді, онда ол қалған аргументтердің әрқайсысын серверге бөлек датаграммалар ретінде жібереді, содан кейін жауап ретінде серверден алынған датаграммаларды оқиды және шығарады.

Листинг 56.3. Echo UDP қызметіне арналған клиент

#қосуға "id_echo.h"

INT
негізгі(int argc, char *argv[])
{
int sfd, j;
size_tlen;
ssize_t numRead;
charbuf[BUF_SIZE];

егер (argc < 2 || strcmp(argv[1], "--анықтама") == 0)
usageErr("%s хост хабарламасы...n", argv[0]);

/* Бірінші пәрмен жолының аргументі негізінде сервер мекенжайын жасаңыз */
sfd = inetConnect(argv[1], SERVICE, SOCK_DGRAM);
егер (sfd == -1)
fatal («Сервер ұясына қосылу мүмкін емес»);

/* Қалған аргументтерді серверге бөлек датаграммалар ретінде жіберіңіз */
үшін (j = 2; j < argc; j++) {
len = strlen(argv[j]);
егер (write(sfd, argv[j], len) != len)
fatal («жартылай/сәтсіз жазу»);

numRead = оқу(sfd, buf, BUF_SIZE);
егер (numRead == -1)
errExit («оқу»);
printf("[%ld bytes] %.*sn", (ұзын) 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 байт] қош бол

Сізге жақсы оқу тілеймін)

Ақпарат көзі: linux.org.ru