Литмир - Электронная Библиотека
Содержание  
A
A

#include <string.h>

#include <errno.h>

#include <unistd.h>

#include <sys/msg.h>

#define MAX_TEXT 512

struct my_msg_st {

 long int my_msg_type;

 char some_text[MAX_TEXT];

};

int main() {

 int running = 1;

 struct my_msg_st some_data;

 int msgid;

<i> char buffer = [BUFSIZ];</i>

 msgid = msgget((key_t)1234, 0666 | IPC_CREAT);

 if (msgid == -1) {

  fprintf(stderr, &quot;msgget failed with error: %d\n&quot;, errno);

  exit(EXIT_FAILURE);

 }

 while (running) {

<i>  printf(&quot;Enter some text: &quot;);</i>

<i>  fgets(buffer, BUFSIZ, stdin);</i>

<i>  some_data.my_msg_type = 1;</i>

<i>  strcpy(some_data.some_text, buffer);</i>

<i>  if (msgsnd(msgid, (void*)&amp;some_data, MAX_TEXT, 0)) == -1) {</i>

<i>   fpintf(stderr, &quot;msgsnd failed\n&quot;);</i>

<i>   exit(EXIT_FAILURE);</i>

<i>  }</i>

<i>  if (strncmp(buffer, &quot;end&quot;, 3) == 0) {</i>

<i>   running = 0;</i>

<i>  }</i>

 }

 exit(EXIT_SUCCESS);

}

В отличие от примера с каналами, процессам нет нужды предоставлять метод их собственной синхронизации. Это существенное преимущество сообщений по сравнению с каналами.

Если в очереди сообщений есть место, отправитель может создать очередь, поместить в нее какие-либо данные и завершить выполнение еще до того, как начнет выполняться приемник. Первой следует запускать программу-отправителя msg2. Далее приведен пример вывода:

$ <b>./msg2</b>

Enter some text: <b>hello</b>

Enter some text: <b>How are you today?</b>

Enter some text: <b>end</b>

$ <b>./msg1</b>

You wrote: hello

You wrote: How are you today?

You wrote: end

Как это работает

Программа-отправитель создает очередь сообщений с помощью функции

msgget
; далее она добавляет сообщения в очередь, применяя функцию
msgsnd
. Программа-приемник получает идентификатор очереди сообщений с помощью функции
msgget
и получает сообщения до тех пор, пока не будет найден специальный текст
end
. Затем программа приводит все в порядок, удаляя очередь сообщений с помощью функции
msgctl
.

Приложение для работы с базой данных компакт-дисков

Сейчас подходящий момент для модификации вашего приложения, управляющего базой данных компакт-дисков, с помощью средств IPC, с которыми вы познакомились в этой главе.

Вы могли бы применить множество разных комбинаций трех разновидностей средств IPC, но поскольку информация, которую следует передавать, очень мала по объему, есть смысл реализовать передачу запросов и ответов непосредственно с помощью очередей сообщений.

Если объемы данных, которые вы должны передавать, были бы велики, можно было бы рассмотреть передачу реальных данных в совместно используемой памяти, одновременно применяя семафоры или сообщения для отправки маркера или "опознавательного знака", информирующего другой процесс о наличии данных в совместно используемой памяти.

Интерфейс очереди сообщений устраняет проблему, которая у вас была в главе 11, когда вы нуждались в открытом канале у обоих процессов в момент передачи данных. Применение очередей сообщений позволяет одному процессу поместить сообщения в очередь, даже если этот процесс в данный момент — единственный пользователь очереди.

Вам нужно ответить лишь на один важный вопрос: как возвращать ответы клиентам? Простым решением было бы наличие одной очереди для сервера и по одной очереди для каждого клиента. Если одновременно существует много клиентов, такой подход может вызвать проблемы, т.к. потребуется большое количество очередей. Используя в сообщении поле идентификатора сообщения, вы сможете разрешить всем клиентам пользоваться одной очередью и адресовать ответные сообщения конкретным клиентским процессам с помощью включенного в сообщение идентификатора клиентского процесса. Далее каждый клиент может извлекать сообщения, адресованные только ему, оставляя сообщения для других клиентов в очереди.

Для преобразования приложения, работающего с базой данных компакт-дисков, с помощью средств IPC вам придется заменить только файл pipe_imp.c из сопроводительного программного кода к главе 13. Далее мы рассмотрим важные разделы замещающего файла ipc_imp.c.

Пересмотр функций сервера

Сначала нужно обновить серверные функции.

1. Прежде всего, включите необходимые заголовочные файлы, объявите несколько ключей очередей сообщений и структуру для хранения данных сообщения:

#include &quot;cd_data.h&quot;

#include &quot;cliserv.h&quot;

#include &lt;sys/msg.h&gt;

#define SERVER_MQUEUE 1234

#define CLIENT_MQUEUE 4321

struct msg_passed {

 long int msg_key; /* Используется для клиентского pid */

 message_db_t real message;

};

2. Две глобальные переменные хранят идентификаторы двух очередей, возвращаемые функцией

msgget
:

static int serv_qid = -1;

static int cli_qid = -1;

259
{"b":"285844","o":1}