Книга „Linux API. Сеопфатен водич»


Книга „Linux API. Сеопфатен водич»

Добар ден Ви ја пренесувам книгата „Linux API. Сеопфатен водич “(превод на книгата Програмскиот интерфејс Линукс). Може да се нарача на веб-страницата на издавачот и доколку го примените промотивниот код LinuxAPI ќе добиете попуст од 30%.

Извадок од книгата за преглед:

Сокети: архитектура на серверот

Во ова поглавје, ќе разговараме за основите на дизајнирање на итеративни и паралелни сервери, како и за посебен демон кој го олеснува создавањето на Интернет апликации од страна на серверот.

Итерација и паралелни сервери

Постојат две вообичаени архитектури на мрежни сервери базирани на сокет:

  • итеративно: серверот ги опслужува клиентите еден по еден, прво обработувајќи го барањето (или неколку барања) на еден клиент, а потоа преминува на следниот;

  • паралелно: серверот е дизајниран да опслужува повеќе клиенти во исто време.

Делот 44.8 веќе даде пример на сервер за повторување базиран на редици FIFO.

Серверите за повторување обично се погодни само во ситуации кога барањата на клиентот може да се обработат прилично брзо, бидејќи секој клиент треба да почека додека не бидат опслужени сите други клиенти пред него. Вообичаен случај на употреба за овој пристап е да се разменуваат единечни барања и одговори помеѓу клиентот и серверот.

Паралелните сервери се погодни во случаи кога секое барање бара значително време за обработка, или клиентот и серверот имаат долга размена на пораки. Во ова поглавје, главно ќе се фокусираме на традиционалниот (и најлесниот) начин за дизајнирање на паралелни сервери, а тоа е создавање на посебен дете процес за секој нов клиент. Таквиот процес ја врши целата работа за услужување на клиентот, по што завршува. Бидејќи секој од овие процеси работи независно, можно е да се опслужуваат повеќе клиенти во исто време. Главната задача на главниот процес на сервер (родител) е да создаде посебно дете за секој нов клиент (алтернативно, наместо процеси, можете да креирате нишки за извршување).

Во следните делови, ќе разгледаме примери на итеративни и паралелни сервери базирани на приклучоци за домен на интернет. Овие два сервери имплементираат поедноставена верзија на услугата ехо (RFC 862) која враќа копија од која било порака испратена до неа од клиентот.

ехо повторување udp сервер

Во овој и следниот дел ќе воведеме сервери за услугата ехо. Достапно е на портата број 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.ч

Списокот 56.2-XNUMX ја прикажува имплементацијата на серверот. Вреди да се забележат следниве точки:

  • за да го ставиме серверот во режим на демон, ја користиме функцијата beneDaemon() од Дел 37.2;

  • за да ја направиме програмата покомпактна, ја користиме библиотеката со штекери за интернет домен развиена во делот 55.12;

  • ако серверот не може да врати одговор на клиентот, тој пишува порака во дневникот користејќи го повикот syslog().

Во вистинска апликација, најверојатно ќе наметнеме одредено ограничување на фреквенцијата на евиденција на пораки користејќи syslog(). Ова би ја елиминирало можноста напаѓачот да го преполни системскиот дневник. Исто така, имајте на ум дека секој повик syslog() е прилично скап, бидејќи стандардно користи fsync().

Листа 56.2. Сервер за повторување што ја имплементира услугата echo UDP

_________________________________________________________________ приклучоци/id_echo_sv.c
#вклучи
#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;
шарбаф[BUF_SIZE];
char addrStr[IS_ADDR_STR_LEN];

ако (стане Демон (0) == -1)
errExit ("стане Демон");

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");
ако (испрати (sfd, buf, numRead, 0, (struct sockaddr *) &claddr, len)
!=numПрочитај)
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. Клиент за услугата ехо UDP

#include "id_echo.h"

int
main (int argc, char *argv[])
{
int sfd,j;
големина_тлен;
ssize_t numRead;
шарбаф[BUF_SIZE];

ако (argc < 2 || strcmp(argv[1], "--помош") == 0)
usageErr(„%s msg host…n“, argv[0]);

/* Формирајте ја адресата на серверот врз основа на аргументот на првата командна линија */
sfd = inetConnect(argv[1], SERVICE, SOCK_DGRAM);
ако (sfd == -1)
fatal ("Не можев да се поврзам со серверот");

/* Остатокот од аргументите испратете ги до серверот како посебни датаграми */
за (j = 2; j < argc; j++) {
len = strlen(argv[j]);
ако (напиши (sfd, argv[j], len) != len)
фатална ("делумно/неуспешно пишување");

numRead = читање (sfd, buf, BUF_SIZE);
ако (numRead == -1)
errExit ("читај");
printf("[%ld bytes] %.*sn", (долго) numRead, (int) numRead, buf);
}
излез (EXIT_SUCCESS);
}
_________________________________________________________________ приклучоци/id_echo_cl.в

Следното е пример за тоа што ќе видиме кога ќе го стартуваме серверот и две инстанци на клиентот:

$ su // Потребни се привилегии за да се поврзе со резервирана порта
Лозинка:
# ./id_echo_sv // Серверот оди во позадина
# излез // Откажи ги административните права
$ ./id_echo_cl localhost hello world // Овој клиент испраќа два датаграми
[5 бајти] здраво // Клиентот го прикажува одговорот добиен од серверот
[5 бајти] свет
$ ./id_echo_cl localhost збогум // Овој клиент испраќа еден датаграм
[7 бајти] збогум

Ви посакувам пријатно читање)

Извор: linux.org.ru