Linux API kitab. Hərtərəfli bələdçi »


Linux API kitab. Hərtərəfli bələdçi »

Günortanız Xeyir Diqqətinizə “Linux API. Hərtərəfli bələdçi "(kitabın tərcüməsi Linux proqramlaşdırma interfeysi). Bu, naşirin saytında sifariş verilə bilər və promo kodu tətbiq etsəniz LinuxAPI 30% endirim əldə edəcəksiniz.

Baxış üçün kitabdan bir parça:

Soketlər: server arxitekturası

Bu fəsildə biz iterativ və paralel serverlərin layihələndirilməsinin əsaslarını, həmçinin server tərəfində olan İnternet proqramlarının yaradılmasını asanlaşdıran xüsusi inetd demonunu müzakirə edəcəyik.

İterasiya və Paralel Serverlər

İki ümumi soket əsaslı şəbəkə server arxitekturası var:

  • iterativ: server müştərilərə bir-bir xidmət göstərir, əvvəlcə bir müştərinin sorğusunu (və ya bir neçə sorğunu) emal edir və sonra digərinə keçir;

  • paralel: server eyni vaxtda bir neçə müştəriyə xidmət etmək üçün nəzərdə tutulub.

Bölmə 44.8 artıq FIFO növbələrinə əsaslanan iterasiya serverinin nümunəsini təqdim etmişdir.

İterasiya serverləri adətən yalnız müştəri sorğularının kifayət qədər tez emal oluna biləcəyi vəziyyətlərdə uyğundur, çünki hər bir müştəri qarşısındakı hər hansı digər müştərilərə xidmət göstərilənə qədər gözləməli olur. Bu yanaşma üçün ümumi istifadə halı müştəri və server arasında tək sorğu və cavabların mübadiləsidir.

Paralel serverlər hər bir sorğunun işlənməsi üçün xeyli vaxt tələb etdiyi və ya müştəri ilə server arasında uzun müddət mesaj mübadiləsi olduğu hallarda uyğundur. Bu fəsildə biz əsasən paralel serverlərin dizaynının ənənəvi (və ən asan) yoluna, yəni hər yeni müştəri üçün ayrıca uşaq prosesinin yaradılmasına diqqət yetirəcəyik. Belə bir proses müştəriyə xidmət göstərməklə bağlı bütün işləri yerinə yetirir, bundan sonra başa çatır. Bu proseslərin hər biri müstəqil işlədiyi üçün eyni vaxtda bir neçə müştəriyə xidmət göstərmək mümkündür. Əsas server prosesinin (valideyn) əsas vəzifəsi hər bir yeni müştəri üçün ayrıca uşaq yaratmaqdır (bir seçim olaraq, proseslərin yerinə icra ipləri yarada bilərsiniz).

Növbəti bölmələrdə biz internet domen soketlərinə əsaslanan iterativ və paralel serverlərin nümunələrinə baxacağıq. Bu iki server müştəri tərəfindən ona göndərilən istənilən mesajın surətini qaytaran echo xidmətinin (RFC 862) sadələşdirilmiş versiyasını həyata keçirir.

echo iteration udp server

Bu və növbəti bölmədə biz echo xidməti üçün serverləri təqdim edəcəyik. O, 7 nömrəli portda mövcuddur və həm UDP, həm də TCP üzərində işləyir (bu port qorunur və buna görə də əks-səda serveri administrator imtiyazları ilə işlədilməlidir).

Echo UDP serveri daim dataqramları oxuyur və onların surətini göndərənə qaytarır. Serverin hər dəfə yalnız bir mesajı emal etməsi lazım olduğundan, burada təkrarlanan arxitektura kifayət edəcəkdir. Serverlər üçün başlıq faylı Siyahı 56.1-XNUMX-də göstərilmişdir.

Siyahı 56.1. id_echo_sv.c və id_echo_cl.c proqramları üçün başlıq faylı

#include "inet_sockets.h" /* Soket funksiyalarımızı elan edir */
# "tlpi_hdr.h" daxil edin

#define SERVICE "echo" /* UDP xidmət adı */

#define BUF_SIZE 500 /* Dataqramların maksimum ölçüsü
müştəri və server tərəfindən oxuna bilər */
______________________________________________________________________ prizlər/id_echo.h

Siyahı 56.2-XNUMX server tətbiqini göstərir. Aşağıdakı məqamları qeyd etməyə dəyər:

  • serveri demon rejiminə keçirmək üçün biz Bölmə 37.2-dən olmaqDaemon() funksiyasından istifadə edirik;

  • proqramı daha yığcam etmək üçün biz bölmə 55.12-də hazırlanmış internet domen yuvası kitabxanasından istifadə edirik;

  • server müştəriyə cavab qaytara bilmirsə, syslog() çağırışından istifadə edərək jurnala mesaj yazır.

Həqiqi bir tətbiqdə biz çox güman ki, syslog() funksiyasından istifadə edərək mesajların qeyd edilməsi tezliyinə müəyyən məhdudiyyət qoyardıq. Bu, təcavüzkarın sistem jurnalını aşması ehtimalını aradan qaldıracaq. Həmçinin unutmayın ki, hər bir syslog() zəngi kifayət qədər bahadır, çünki o, standart olaraq fsync() istifadə edir.

Siyahı 56.2. Echo UDP xidmətini həyata keçirən iterasiya serveri

_________________________________________________________________sockets/id_echo_sv.c
#daxildir
# "id_echo.h" daxil edin
#daxil edin "become_daemon.h"

int
əsas(int argc, char *argv[])
{
int sfd;
ssize_t numOxu;
socklen_tlen;
struct sockaddr_storage claddr;
charbuf[BUF_SIZE];
char addrStr[IS_ADDR_STR_LEN];

əgər (Daemon olmaq(0) == -1)
errExit("Daemon olmaq");

sfd = inetBind(SERVICE, SOCK_DGRAM, NULL);
əgər (sfd == -1) {
syslog(LOG_ERR, "Server yuvası (%s) yaratmaq mümkün olmadı",
strerror (səhv));
çıxış(EXIT_FAILURE);

/* Dataqramları qəbul edin və nüsxələrini göndərənlərə qaytarın */
}
üçün(;;) {
len = sizeof(struct sockaddr_storage);
numRead = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *) &claddr, &len);

əgər (numRead == -1)
errExit("recvfrom");
əgər (sendto(sfd, buf, numRead, 0, (struct sockaddr *) &claddr, len)
!=numOxu)
syslog(LOG_WARNING, "%s (%s) üçün cavabın əks-sədalanması xətası",
inetAddressStr((struct sockaddr *) &claddr, len,
addrStr, IS_ADDR_STR_LEN),
strerror (səhv));
}
}
_________________________________________________________________sockets/id_echo_sv.c

Serveri sınamaq üçün 56.3 siyahısında proqramdan istifadə edirik. O, həmçinin Bölmə 55.12-də hazırlanmış İnternet domen yuvası kitabxanasından istifadə edir. Müştəri proqramı əmr satırında birinci arqument kimi serverin yerləşdiyi şəbəkə hostunun adını alır. Müştəri, qalan arqumentlərin hər birini ayrı-ayrı dataqramlar kimi serverə göndərdiyi dövrəyə daxil olur və sonra cavab olaraq serverdən alınan dataqramları oxuyub çıxarır.

Siyahı 56.3. Echo UDP xidməti üçün müştəri

# "id_echo.h" daxil edin

int
əsas(int argc, char *argv[])
{
int sfd, j;
size_tlen;
ssize_t numOxu;
charbuf[BUF_SIZE];

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

/* Birinci komanda xətti arqumentinə əsasən server ünvanını yaradın */
sfd = inetConnect(argv[1], SERVICE, SOCK_DGRAM);
əgər (sfd == -1)
ölümcül("Server yuvasına qoşulmaq mümkün olmadı");

/* Qalan arqumentləri serverə ayrıca dataqramlar kimi göndərin */
üçün (j = 2; j < argc; j++) {
len = strlen(argv[j]);
əgər (write(sfd, argv[j], len) != len)
ölümcül("qismən/uğursuz yazma");

numRead = oxumaq (sfd, buf, BUF_SIZE);
əgər (numRead == -1)
errExit("oxumaq");
printf("[%ld bytes] %.*sn", (uzun) numRead, (int) numRead, buf);
}
çıxış(EXIT_SUCCESS);
}
_________________________________________________________________sockets/id_echo_cl.c

Aşağıdakılar serveri və iki müştəri nümunəsini işə saldıqda görəcəyimizə bir nümunədir:

$ su // Qorunan porta qoşulmaq üçün imtiyazlar tələb edir
Şifrə:
# ./id_echo_sv // Server arxa plana keçir
# exit // Admin hüquqlarından imtina edin
$ ./id_echo_cl localhost salam dünya // Bu müştəri iki dataqram göndərir
[5 bayt] salam // Müştəri serverdən alınan cavabı çıxarır
[5 bayt] dünya
$ ./id_echo_cl localhost vida // Bu müştəri bir dataqram göndərir
[7 bayt] sağol

Sizə xoş oxu arzulayıram)

Mənbə: linux.org.ru