Материал: 6262

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

186

в дальнейшем для других операций с ней.

Здесь параметр key - ключ System V IPC для очереди сообщений.

Замечание

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

Параметр msgflg – имеет значение только при создании новой очереди сообщений и определяет права различных пользователей при доступе к очереди, а также необходимость создания новой очереди и поведение системного вызова при попытке создания. Он является некоторой комбинацией, с помощью операции побитовое или – " | ", следующих предопределенных значений и восьмеричных прав доступа:

IPC_CREAT — если очереди для указанного ключа не существует, она должна быть создана;

IPC_EXCL — применяется совместно с флагом IPC_CREAT. При совместном

их использовании и существовании массива с указанным ключом доступ к очереди не производится и констатируется ошибочная ситуация, при этом переменная errno, описанная в файле <errno.h>, примет значение EEXIST;

0400 — разрешено чтение для пользователя, создавшего очередь;

0200 — разрешена запись для пользователя, создавшего очередь;

0040 — разрешено чтение для группы пользователя, создавшего очередь;

0020 — разрешена запись для группы пользователя, создавшего очередь;

0004 — разрешено чтение для всех остальных пользователей;

0002 — разрешена запись для всех остальных пользователей.

Замечание

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

ipcs -l

Системный вызов msgget() возвращает:

значение дескриптора System V IPC для очереди сообщений, при нормальном завершении;

значение -1, при возникновении ошибки.

Системный вызов msgsnd() предназначен для помещения сообщения в очередь сообщений.

int msgsnd(int msqid, struct msgbuf *ptr, int length, int flag);

Параметр msqid является дескриптором System V IPC для очереди, в которую

187

отправляется сообщение.

Непосредственно, данные передаются структуры типа struct msgbuf, которая описана в файле <sys/msg.h> как

struct msgbuf { long mtype; char mtext[1];

};

где mtype - имеет тип long, интерпретируемый как тип сообщения; должен быть

строго положительной величиной.

mtext[...] - массив байт передаваемого сообщения; в Linux, назмер этого массива ограничен размером 4080 байт и может быть еще уменьшен системным администратором.

Например:

struct mymsgbuf { long mtype;

char mtext[1024]; } mybuf;

Более того, информация вовсе не обязана быть текстовой, например:

struct mymsgbuf { long mtype; struct {

int iinfo; float finfo;

}info;

}mybuf;

Параметр length — действительная длинна полезной информации, которая следует за типом сообщения, в структуре msgbuf.

Параметр flag может принимать два значения: 0 и IPC_NOWAIT:

если значение флага равно 0, и в очереди не хватает места для того, чтобы

поместить сообщение, то системный вызов блокируется до тех пор, пока не освободится место;

при значении флага IPC_NOWAIT системный вызов в этой ситуации не

блокируется, а констатируется возникновение ошибки с установлением значения переменной errno, описанной в файле <errno.h>, равным EAGAIN.

Системный вызов msgsnd() возвращает:

значение 0, при нормальном завершении;

значение -1, при возникновении ошибки.

Системный вызов msgrcv() предназначен для получения сообщения из очереди сообщений.

int msgrcv(int msqid, struct msgbuf *ptr, int length, long type, int flag);

188

где параметр msqid - дескриптор System V IPC очереди, из которой извлекается сообщение;

type - способ выборки сообщения из очереди:

0 - в порядке FIFO, независимо от типа сообщения;

n - в порядке FIFO, для сообщений с типом n;

-n - первым выбирается сообщение с минимальным типом, не превышающим

значения n, пришедшее ранее всех других сообщений с тем же типом.

length - максимальная длина полезной части информации, расположенной в структуре после типа сообщения, которая может быть размещена в сообщении. Параметр flag может принимать значение 0 или быть какой-либо комбинацией флагов IPC_NOWAIT и MSG_NOERROR:

Если флаг IPC_NOWAIT не установлен и очередь сообщений пуста или в ней

нет сообщений с заказанным типом, то системный вызов блокируется до появления запрошенного сообщения.

При установлении флага IPC_NOWAIT системный вызов в этой ситуации не

блокируется, а констатирует возникновение ошибки с установлением значения переменной errno, описанной в файле <errno.h>, равным EAGAIN.

Если действительная длина полезной части информации в выбранном

сообщении превышает значение, указанное в параметре length и флаг MSG_NOERROR не установлен, то выборка сообщения не производится, и фиксируется наличие ошибочной ситуации.

Если флаг MSG_NOERROR установлен, то в этом случае ошибки не возникает, а сообщение копируется в сокращенном виде.

Вслучае удачи, системный вызов msgrcv() копирует выбранное сообщение из очереди сообщений по адресу, указанному в параметре ptr, одновременно удаляя его из очереди сообщений.

Системный вызов msgrcv() возвращает:

действительную длину полезной части информации, при нормальном завершении;

значение -1, при возникновении ошибки.

Системный вызов msgctl() предназначен для получения информации об очереди сообщений, изменения ее атрибутов и удаления из системы.

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

где msqid - дескриптор System V IPC, которое вернул системный вызов msgget() при создании очереди или при ее поиске по ключу;

cmd - используется как команда (см. руководство man).

Замечание

IPC_RMID – команда для удаления очереди сообщений с заданным идентификатором. Параметр buf для этой команды не используется, поэтому мы всегда будем подставлять туда значение NULL.

189

Системный вызов msgctl() возвращает:

значение 0, при нормальном завершении;

значение -1, при возникновении ошибки.

Рассморим практическое применение очередей сообщений, на примере работы двух программ:

программа lab11.5, показанная на листинге 5.5, пишет в очередь ряд сообщений с типом 0 и заканчивает запись в очередь сообщением с типом 255;

программа lab11.6, показанная на листинге 5.6, читает из очереди все сооб-

щения и печатает их; чтение сообщений заканчивается, когда получено сообщение с типом 255;

Листринг 5.5 - Текст программы, которая пишет сообщения в очередь

/** Программа lab11.5, иллюстрирующая запись очереди сообщений.

*

*она получает доступ к очереди сообщений, отправляет в нее 5 текстовых сообщений

*с типом 1 и одно пустое сообщение с типом 255,

*которое будет служить для программы lab11.5

*сигналом прекращения работы. */

#include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <string.h> #include <stdio.h>

/* Тип сообщения для прекращения работы программы lab11.6 */ #define LAST_MESSAGE 255

int main()

{

int msqid; // IPC дескриптор для очереди сообщений

//Имя файла, использующееся для генерации ключа.

//Файл с таким именем должен существовать

char pathname[] = "/home/upk/lab11"; key_t key; // IPC ключ

int i,len; // Счетчик цикла и длина информативной части сообщения

/* Пользовательская структура для сообщения */ struct mymsgbuf

{

long mtype; char mtext[81];

} mybuf;

/* Массив сообщений */ char mesg[5][81] = {

"Сообщение один.", "Сообщение два.", "Сообщение три.", "Сообщение четыре.", "Сообщение пять."

};

printf("lab11.5: Начинаю работу...\n");

// Генерируем IPC ключ из имени файла и номера экземпляра очереди сообщений 0.

190

if((key = ftok(pathname,0)) < 0){ printf("Не могу сгенерировать key\n"); exit(-1);

}

//Получаем доступ по ключу к очереди сообщений, если она существует,

//или создать ее, с правами доступа read & write для всех пользователей if((msqid = msgget(key, 0666 | IPC_CREAT)) < 0){

printf("Не могу получить msqid\n"); exit(-1);

}

// Посылаем в цикле 5 сообщений с типом 1 в очередь сообщений. for (i = 0; i < 5; i++){

/* Сначала заполняем структуру для нашего сообщения и определяем длину информативной части */ mybuf.mtype = 1;

strcpy(mybuf.mtext, mesg[i]); len = strlen(mybuf.mtext)+1;

//Отсылаем сообщение. В случае ошибки сообщаем об

//этом и удаляем очередь сообщений из системы.

if (msgsnd(msqid, (struct msgbuf *) &mybuf, len, 0) < 0){ printf("Не могу послать сообщение в очередь\n"); msgctl(msqid, IPC_RMID,

(struct msqid_ds *) NULL); exit(-1);

}

printf("Записал в очередь: %s\n", mesg[i]);

}

//Отсылаем сообщение, которое заставит получающий процесс

//прекратить работу, с типом LAST_MESSAGE и длиной 0 mybuf.mtype = LAST_MESSAGE;

len = 0;

if (msgsnd(msqid, (struct msgbuf *) &mybuf, len, 0) < 0){

printf("Не могу послать сообщение в очередь\n"); msgctl(msqid, IPC_RMID, (struct msqid_ds *) NULL); exit(-1);

}

printf("Записал в очередь: пустое сообщение\n"); printf("lab11.5: Закончила работу...\n"); return 0;

}

На рисунке 5.1 показан вывод этой программы.

Рисунок 5.1 — Вывод программы пишущей сообщения

Источник: https://studfile.net/preview/16438530/