Читаем Linux API. Исчерпывающее руководство полностью

umask(0); /* Получаем нужные нам права доступа */

if (mkfifo(SERVER_FIFO, S_IRUSR | S_IWUSR | S_IWGRP) == -1

&& errno!= EEXIST)

errExit("mkfifo %s", SERVER_FIFO);

serverFd = open(SERVER_FIFO, O_RDONLY);

if (serverFd == -1)

errExit("open %s", SERVER_FIFO);

/* Открываем дополнительный записывающий дескриптор,

чтобы никогда не получить символ конца файла */

dummyFd = open(SERVER_FIFO, O_WRONLY);

if (dummyFd == -1)

errExit("open %s", SERVER_FIFO);

if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)

errExit("signal");

for (;;) { /* Считываем запросы и отправляем ответы */

if (read(serverFd, &req, sizeof(struct request))

!= sizeof(struct request)) {

fprintf(stderr, "Error reading request; discarding\n");

continue; /* Либо частичное прочтение, либо ошибка */

}

/* Открываем клиентскую очередь FIFO (предварительно созданную клиентом) */

 snprintf(clientFifo, CLIENT_FIFO_NAME_LEN, CLIENT_FIFO_TEMPLATE,

(long) req.pid);

 clientFd = open(clientFifo, O_WRONLY);

if (clientFd == -1) { /* Открыть не удалось, отклоняем запрос */

errMsg("open %s", clientFifo);

 continue;

}

/* Отправляем ответ и закрываем очередь FIFO */

resp.seqNum = seqNum;

if (write(clientFd, &resp, sizeof(struct response))

!= sizeof(struct response))

fprintf(stderr, "Error writing to FIFO %s\n", clientFifo);

if (close(clientFd) == -1)

errMsg("close");

seqNum += req.seqLen; /* Обновляем номер нашей последовательности */

}

}

pipes/fifo_seqnum_server.c

Клиентская программа

В листинге 44.8 приведен код клиента, выполняющего следующие действия.

• Создает очередь FIFO, которая будет использоваться для получения ответа от сервера . Это делается до отправки запроса, чтобы на момент, когда сервер попытается ее открыть и послать сообщение, очередь уже существовала.

• Создает сообщение для сервера, состоящее из идентификатора клиентского процесса и числа (взятого из опционального аргумента командной строки), обозначающего длину последовательности, которую клиент хочет получить от сервера (если аргумент командной строки не указан, по умолчанию берется длина 1).

• Открывает серверную очередь FIFO и отправляет серверу сообщение .

• Открывает клиентскую очередь FIFO , считывает и выводит ответ сервера .

Еще один момент, на который стоит обратить внимание, — обработчик выхода . Он устанавливается с помощью вызова atexit() и следит за тем, чтобы при завершении клиентского процесса его очередь FIFO была удалена. Как вариант можно было бы просто добавить вызов unlink() сразу после открытия клиентской очереди. Такой подход сработал бы, ведь на данном этапе клиент и сервер уже выполнили бы блокирующие вызовы open() и обладали бы открытыми файловыми дескрипторами для очереди; кроме того, удаление имени очереди FIFO из файловой системы не повлияло бы на эти дескрипторы (или на открытые файловые дескрипторы, на которые они указывают).

Вот пример того, что можно увидеть при запуске клиентской и серверной программ:

$ ./fifo_seqnum_server &

[1] 5066

$ ./fifo_seqnum_client 3 Запрашиваем последовательность из трех чисел

Назначенная последовательность начинается с 0

$ ./fifo_seqnum_client 2 Запрашиваем последовательность из двух чисел

Назначенная последовательность начинается с 3

$ ./fifo_seqnum_client Запрашиваем одно число

5

Листинг 44.8. Клиент для сервера, генерирующего числовые последовательности

pipes/fifo_seqnum_client.c

#include "fifo_seqnum.h"

static char clientFifo[CLIENT_FIFO_NAME_LEN];

static void /* Вызывается при выходе для удаления клиентской очереди FIFO */

removeFifo(void)

{

unlink(clientFifo);

}

int

main(int argc, char *argv[])

{

int serverFd, clientFd;

struct request req;

struct response resp;

if (argc > 1 && strcmp(argv[1], " — help") == 0)

usageErr("%s [seq-len…]\n", argv[0]);

/* Создаем нашу очередь FIFO (до отправки запроса, чтобы избежать состояния гонки) */

umask(0); /* Получаем нужные нам права доступа */

snprintf(clientFifo, CLIENT_FIFO_NAME_LEN, CLIENT_FIFO_TEMPLATE,

(long) getpid());

if (mkfifo(clientFifo, S_IRUSR | S_IWUSR | S_IWGRP) == -1

&& errno!= EEXIST)

errExit("mkfifo %s", clientFifo);

if (atexit(removeFifo)!= 0)

errExit("atexit");

/* Создаем запрос, открываем серверную очередь FIFO и отправляем запрос */

req.pid = getpid();

req.seqLen = (argc > 1)? getInt(argv[1], GN_GT_0, "seq-len"): 1;

serverFd = open(SERVER_FIFO, O_WRONLY);

if (serverFd == -1)

errExit("open %s", SERVER_FIFO);

if (write(serverFd, &req, sizeof(struct request))!=

sizeof(struct request))

fatal("Can't write to server");

/* Открываем нашу очередь FIFO, считываем и выводим ответ */

clientFd = open(clientFifo, O_RDONLY);

if (clientFd == -1)

errExit("open %s", clientFifo);

if (read(clientFd, &resp, sizeof(struct response))

!= sizeof(struct response))

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных