Գիրք «Linux API. Համապարփակ ուղեցույց»


Գիրք «Linux API. Համապարփակ ուղեցույց»

Բարի օր Ձեր ուշադրությանն եմ ներկայացնում «Linux API. Համապարփակ ուղեցույց» (գրքի թարգմանությունը Linux ծրագրավորման ինտերֆեյս) Այն կարելի է պատվիրել հրատարակչի կայքում, և եթե կիրառեք գովազդային կոդը LinuxAPI , կստանաք 30% զեղչ։

Հատված գրքից տեղեկանքի համար.

Sockets. Server Architecture

Այս գլխում մենք կքննարկենք կրկնվող և զուգահեռ սերվերների նախագծման հիմունքները, ինչպես նաև կանդրադառնանք inetd կոչվող հատուկ դեմոնին, որը հեշտացնում է ինտերնետ սերվերի հավելվածների ստեղծումը:

Կրկնվող և զուգահեռ սերվերներ

Գոյություն ունեն վարդակների վրա հիմնված ցանցային սերվերի երկու ընդհանուր ճարտարապետություն.

  • կրկնվող. սերվերը սպասարկում է հաճախորդներին մեկ առ մեկ՝ սկզբում մշակելով մեկ հաճախորդի հարցումը (կամ մի քանի հարցում), այնուհետև անցնելով հաջորդին.

  • զուգահեռ. սերվերը նախատեսված է միաժամանակ մի քանի հաճախորդների սպասարկելու համար:

FIFO հերթերի վրա հիմնված կրկնվող սերվերի օրինակ արդեն ներկայացված էր Բաժին 44.8-ում:

Կրկնվող սերվերները սովորաբար հարմար են միայն այն իրավիճակներում, երբ հաճախորդի հարցումները կարող են բավականին արագ մշակվել, քանի որ յուրաքանչյուր հաճախորդ ստիպված է սպասել, մինչև իր առջև գտնվող մյուս հաճախորդները սպասարկվեն: Այս մոտեցման ընդհանուր օգտագործման դեպքը հաճախորդի և սերվերի միջև առանձին հարցումների և պատասխանների փոխանակումն է:

Զուգահեռ սերվերները հարմար են այն դեպքերում, երբ յուրաքանչյուր հարցումը զգալի ժամանակ է պահանջում մշակման համար, կամ երբ հաճախորդը և սերվերը ներգրավված են երկար հաղորդագրությունների փոխանակման մեջ: Այս գլխում մենք հիմնականում կկենտրոնանանք զուգահեռ սերվերների նախագծման ավանդական (և ամենապարզ) ձևի վրա, որը յուրաքանչյուր նոր հաճախորդի համար առանձին երեխա գործընթաց ստեղծելն է: Այս գործընթացը կատարում է բոլոր աշխատանքները հաճախորդին սպասարկելու համար, այնուհետև ավարտվում է: Քանի որ այս գործընթացներից յուրաքանչյուրը գործում է ինքնուրույն, հնարավոր է միաժամանակ սպասարկել բազմաթիվ հաճախորդների: Հիմնական սերվերի գործընթացի (ծնող) հիմնական խնդիրն է յուրաքանչյուր նոր հաճախորդի համար առանձին երեխա ստեղծել (այլընտրանքային տարբերակով, գործընթացների փոխարեն կարող են ստեղծվել կատարման թելեր):

Հաջորդ բաժիններում մենք կանդրադառնանք կրկնվող և զուգահեռ ինտերնետ տիրույթի վարդակից սերվերների օրինակներին: Այս երկու սերվերներն իրականացնում են echo ծառայության պարզեցված տարբերակը (RFC 862), որը վերադարձնում է հաճախորդի կողմից իրեն ուղարկված ցանկացած հաղորդագրության պատճենը:

Կրկնվող UDP սերվերի արձագանք

Այս և հաջորդ բաժնում մենք կներկայացնենք echo ծառայության սերվերները: Այն հասանելի է 7-րդ պորտում և աշխատում է ինչպես UDP-ի, այնպես էլ TCP-ի միջոցով (այս նավահանգիստը վերապահված է, և հետևաբար echo սերվերը պետք է գործարկվի ադմինիստրատորի արտոնություններով):

Echo UDP սերվերը շարունակաբար կարդում է տվյալների գծապատկերները և դրանց պատճենները վերադարձնում ուղարկողին: Քանի որ սերվերը պետք է միաժամանակ մշակի միայն մեկ հաղորդագրություն, կրկնվող ճարտարապետությունը բավարար կլինի: Սերվերների վերնագրի ֆայլը ցուցադրված է Ցուցակ 56.1-ում:

Ցուցակ 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 /* Datagrams-ի առավելագույն չափը, որը
կարելի է կարդալ հաճախորդի և սերվերի կողմից */
__________________________________________________________________վարդակներ/id_echo.h

56.2 ցուցակը ցույց է տալիս սերվերի իրականացումը: Արժե ուշադրություն դարձնել հետևյալ կետերին.

  • սերվերը daemon ռեժիմի մեջ դնելու համար մենք օգտագործում ենք beneDaemon() ֆունկցիան 37.2 բաժնից;

  • Ծրագիրն ավելի կոմպակտ դարձնելու համար մենք օգտագործում ենք գրադարանը ինտերնետ տիրույթի վարդակների հետ աշխատելու համար, որը մշակվել է 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 adrStr[IS_ADDR_STR_LEN];

եթե (դառնա Daemon(0) == -1)
errExit ("դառնալ Daemon");

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 echo ծառայության համար

#include «id_echo.h»

int
հիմնական (int argc, char *argv[])
{
int sfd, j;
size_t len;
ssize_t numRead;
char buf[BUF_SIZE];

եթե (argc < 2 || strcmp(argv[1], «-- օգնություն») == 0)
usageErr("%s host msg…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", (long) numRead, (int) numRead, buf);
}
ելք (EXIT_SUCCESS);
}
__________________________________________________________________վարդակներ/id_echo_cl.c

Ստորև բերված է մի օրինակ, թե ինչ կտեսնենք սերվերը և երկու հաճախորդի օրինակները գործարկելիս.

$su // Պահանջվում են արտոնություններ վերապահված նավահանգիստին միանալու համար
Գաղտնաբառ:
# ./id_echo_sv // Սերվերը անցնում է ֆոնային ռեժիմ
# ելք // Հրաժարվեք ադմինիստրատորի իրավունքներից
$ ./id_echo_cl localhost բարև աշխարհ // Այս հաճախորդը ուղարկում է երկու տվյալների գրամ
[5 բայթ] բարև // Հաճախորդը ցուցադրում է սերվերից ստացված պատասխանը
[5 բայթ] աշխարհ
$ ./id_echo_cl localhost հրաժեշտ // Այս հաճախորդը ուղարկում է մեկ datagram
[7 բայթ] ցտեսություն

Մաղթում եմ ձեզ հաճելի ընթերցանություն)

Source: linux.org.ru