Aklat na "Linux API. Komprehensibong Gabay"


Aklat na "Linux API. Komprehensibong Gabay"

Magandang hapon Ipinakita ko sa iyong pansin ang aklat na “Linux API. Isang komprehensibong gabay" (pagsasalin ng aklat Ang Linux Programming Interface). Maaari itong i-order sa website ng publisher, at kung ilalapat mo ang code na pang-promosyon LinuxAPI , makakatanggap ka ng 30% na diskwento.

Sipi mula sa libro para sa sanggunian:

Mga Socket: Arkitektura ng Server

Sa kabanatang ito, tatalakayin natin ang mga pangunahing kaalaman sa pagdidisenyo ng mga iterative at parallel na server, at titingnan din ang isang espesyal na daemon na tinatawag na inetd, na nagpapadali sa paglikha ng mga application ng Internet server.

Iterative at parallel na mga server

Mayroong dalawang karaniwang socket-based network server architectures:

  • umuulit: ang server ay nagsisilbi sa mga kliyente nang paisa-isa, unang nagpoproseso ng isang kahilingan (o ilang mga kahilingan) mula sa isang kliyente at pagkatapos ay lumipat sa susunod;

  • parallel: ang server ay idinisenyo upang maghatid ng maraming kliyente nang sabay-sabay.

Ang isang halimbawa ng isang umuulit na server batay sa mga pila ng FIFO ay ipinakita na sa Seksyon 44.8.

Ang mga iterative server ay kadalasang angkop lamang sa mga sitwasyon kung saan ang mga kahilingan ng kliyente ay maaaring maproseso nang medyo mabilis, dahil ang bawat kliyente ay napipilitang maghintay hanggang sa anumang iba pang mga kliyente sa harap nito ay maihatid. Ang isang karaniwang kaso ng paggamit para sa diskarteng ito ay ang pagpapalitan ng mga iisang kahilingan at tugon sa pagitan ng isang kliyente at server.

Ang mga parallel server ay angkop sa mga kaso kung saan ang bawat kahilingan ay tumatagal ng isang malaking halaga ng oras upang maproseso, o kung saan ang kliyente at server ay nakikibahagi sa mahabang pagpapalitan ng mensahe. Sa kabanatang ito, pangunahin nating tututukan ang tradisyonal (at pinakasimpleng) paraan ng pagdidisenyo ng mga parallel na server, na lumikha ng isang hiwalay na proseso ng bata para sa bawat bagong kliyente. Ginagawa ng prosesong ito ang lahat ng gawain para pagsilbihan ang kliyente at pagkatapos ay matatapos. Dahil ang bawat isa sa mga prosesong ito ay gumagana nang nakapag-iisa, posible na maghatid ng maraming kliyente nang sabay-sabay. Ang pangunahing gawain ng pangunahing proseso ng server (magulang) ay lumikha ng isang hiwalay na bata para sa bawat bagong kliyente (sa kahalili, ang mga thread ng pagpapatupad ay maaaring malikha sa halip na mga proseso).

Sa mga sumusunod na seksyon, titingnan natin ang mga halimbawa ng umuulit at magkatulad na internet domain socket server. Ang dalawang server na ito ay nagpapatupad ng pinasimpleng bersyon ng serbisyo ng echo (RFC 862), na nagbabalik ng kopya ng anumang mensaheng ipinadala dito ng isang kliyente.

Ulit-ulit na UDP server echo

Sa ito at sa susunod na seksyon ay ipakikilala namin ang mga server para sa serbisyo ng echo. Ito ay magagamit sa port number 7 at gumagana sa parehong UDP at TCP (ang port na ito ay nakalaan, at samakatuwid ang echo server ay dapat na tumakbo nang may mga pribilehiyo ng administrator).

Ang echo UDP server ay patuloy na nagbabasa ng mga datagram at nagbabalik ng mga kopya ng mga ito sa nagpadala. Dahil kailangan lang ng server na magproseso ng isang mensahe sa isang pagkakataon, sapat na ang isang umuulit na arkitektura. Ang header file para sa mga server ay ipinapakita sa Listahan 56.1.

Listahan 56.1. Header file para sa mga program na id_echo_sv.c at id_echo_cl.c

#include "inet_sockets.h" /* Ipinapahayag ang mga function ng aming socket */
#include "tlpi_hdr.h"

#define SERVICE "echo" /* Pangalan ng serbisyo ng UDP */

#define BUF_SIZE 500 /* Pinakamataas na laki ng mga datagram na iyon
mababasa ng kliyente at server */
_____________________________________________________________________sockets/id_echo.h

Ipinapakita ng listahan 56.2 ang pagpapatupad ng server. Ang mga sumusunod na punto ay dapat tandaan:

  • upang ilagay ang server sa daemon mode, ginagamit namin ang function na becomeDaemon() mula sa seksyon 37.2;

  • upang gawing mas compact ang program, ginagamit namin ang library para sa pagtatrabaho sa mga socket ng domain ng Internet, na binuo sa seksyon 55.12;

  • kung hindi maibalik ng server ang tugon sa kliyente, magsusulat ito ng mensahe sa log gamit ang syslog() na tawag.

Sa isang tunay na aplikasyon, malamang na magpataw kami ng ilang limitasyon sa dalas ng pag-log ng mga mensahe gamit ang syslog(). Aalisin nito ang posibilidad ng isang umaatake na umapaw sa log ng system. Bilang karagdagan, huwag kalimutan na ang bawat tawag sa syslog() ay medyo mahal, dahil gumagamit ito ng fsync() bilang default.

Listahan 56.2. Server ng pag-ulit na nagpapatupad ng serbisyo ng UDP echo

_________________________________________________________________socket/id_echo_sv.c
#isama
#include "id_echo.h"
#include "become_daemon.h"

int
main(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];

kung (magingDaemon(0) == -1)
errExit("becomeDaemon");

sfd = inetBind(SERVICE, SOCK_DGRAM, NULL);
kung (sfd == -1) {
syslog(LOG_ERR, "Hindi makalikha ng socket ng server (%s)",
strerror(errno));
exit(EXIT_FAILURE);

/* Tumanggap ng mga datagram at ibalik ang mga kopya nito sa mga nagpapadala */
}
para kay (;;) {
len = sizeof(struct sockaddr_storage);
numRead = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *) &claddr, &len);

kung (numRead == -1)
errExit("recvfrom");
if (sendto(sfd, buf, numRead, 0, (struct sockaddr *) &claddr, len)
!= numRead)
syslog(LOG_WARNING, "Error sa pag-echo ng tugon sa %s (%s)",
inetAddressStr((struct sockaddr *) &claddr, len,
addrStr, IS_ADDR_STR_LEN),
strerror(errno));
}
}
_________________________________________________________________socket/id_echo_sv.c

Upang subukan ang pagpapatakbo ng server, ginagamit namin ang program mula sa Listing 56.3. Ginagamit din nito ang library para sa pagtatrabaho sa mga socket ng domain ng Internet, na binuo sa seksyon 55.12. Bilang unang argumento ng command line, kinukuha ng client program ang pangalan ng network node kung saan matatagpuan ang server. Ang kliyente ay pumapasok sa isang loop kung saan ipinapadala nito ang bawat isa sa natitirang mga argumento sa server bilang hiwalay na mga datagram, at pagkatapos ay binabasa at ipi-print ang mga datagram na natatanggap nito mula sa server bilang tugon.

Listahan 56.3. Kliyente para sa serbisyo ng echo ng UDP

#include "id_echo.h"

int
main(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 host msg…n", argv[0]);

/* Bumuo ng address ng server batay sa unang argumento ng command line */
sfd = inetConnect(argv[1], SERBISYO, SOCK_DGRAM);
kung (sfd == -1)
fatal("Hindi makakonekta sa socket ng server");

/* Ipadala ang natitirang mga argumento sa server sa anyo ng magkahiwalay na datagrams */
para sa (j = 2; j < argc; j++) {
len = strlen(argv[j]);
kung (isulat(sfd, argv[j], len) != len)
fatal("partial/failed write");

numRead = read(sfd, buf, BUF_SIZE);
kung (numRead == -1)
errExit("basahin");
printf("[%ld bytes] %.*sn", (mahaba) numRead, (int) numRead, buf);
}
exit(EXIT_SUCCESS);
}
_________________________________________________________________sockets/id_echo_cl.c

Nasa ibaba ang isang halimbawa ng kung ano ang makikita natin kapag nagpapatakbo ng server at dalawang pagkakataon ng kliyente:

$su // Ang mga pribilehiyo ay kinakailangan upang maiugnay sa isang nakalaan na port
password:
# ./id_echo_sv // Pupunta ang server sa background mode
# exit // Isuko ang mga karapatan ng administrator
$ ./id_echo_cl localhost hello world // Nagpapadala ang kliyenteng ito ng dalawang datagrams
[5 bytes] hello // Ipinapakita ng kliyente ang natanggap na tugon mula sa server
[5 bytes] mundo
$ ./id_echo_cl localhost goodbye // Nagpapadala ang kliyenteng ito ng isang datagram
[7 bytes] paalam

Nais ko sa iyo ng isang kaaya-ayang pagbabasa)

Pinagmulan: linux.org.ru