В этом разделе мы уделим внимание функциям, применяемым для отправки сообщений в очередь и получения их оттуда.
48.5.1. Отправка сообщений
Функция mq_send() добавляет сообщение из буфера msg_ptr в очередь сообщений, на которую ссылается дескриптор mqdes.
#include
int mq_send(mqd_t
unsigned int
Возвращает 0 при успешном завершении или -1 при ошибке
Аргумент msg_len обозначает длину сообщения, на которое указывает msg_ptr. Это значение не должно превышать атрибут mq_msgsize очереди; в противном случае функция mq_send() завершится ошибкой EMSGSIZE. Сообщения нулевой длины являются допустимыми.
Каждое сообщение имеет приоритет (целое положительное число), указанный в аргументе msg_prio. Сообщения в очереди размещаются в порядке убывания приоритета (наименьшим является 0). Когда в очередь добавляется новое сообщение, оно занимает место сразу за всеми сообщениями одного с ним приоритета. Если приложение не нуждается в использовании приоритетов, аргументу msg_prio можно всегда передавать значение 0.
Стандарт SUSv3 позволяет реализации определить максимально возможный приоритет; это делается либо с помощью константы MQ_PRIO_MAX, либо через значение, возвращаемое вызовом sysconf(_SC_MQ_PRIO_MAX). Стандарт SUSv3 требует, чтобы данное ограничение не было меньше 32 (_POSIX_MQ_PRIO_MAX); то есть доступны приоритеты в диапазоне как минимум от 0 до 31. Но реальный диапазон может заметно варьироваться. Например, в Linux эта константа равна 32 768, в Solaris — 32, а в Tru64 — 256.
При заполненной очереди сообщений (то есть достигнутом ограничении mq_maxmsg) дальнейшие вызовы mq_send() будут либо блокироваться, пока в очереди не освободится место, либо немедленно завершаться ошибкой EAGAIN, если был установлен флаг O_NONBLOCK.
Программа, представленная в листинге 48.4, является интерфейсом командной строки к функции mq_send(). Ее использование будет продемонстрировано в следующем разделе.
Листинг 48.4. Запись сообщения в очередь сообщений POSIX
pmsg/pmsg_send.c
#include
#include
#include "tlpi_hdr.h"
static void
usageError(const char *progName)
{
fprintf(stderr, "Usage: %s [-n] mq-name msg [prio]\n", progName);
fprintf(stderr, " — n Use O_NONBLOCK flag\n");
exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
int flags, opt;
mqd_t mqd;
unsigned int prio;
flags = O_WRONLY;
while ((opt = getopt(argc, argv, "n"))!= -1) {
switch (opt) {
case 'n': flags |= O_NONBLOCK; break;
default: usageError(argv[0]);
}
}
if (optind + 1 >= argc)
usageError(argv[0]);
mqd = mq_open(argv[optind], flags);
if (mqd == (mqd_t) -1)
errExit("mq_open");
prio = (argc > optind + 2)? atoi(argv[optind + 2]): 0;
if (mq_send(mqd, argv[optind + 1],
strlen(argv[optind + 1]), prio) == -1)
errExit("mq_send");
exit(EXIT_SUCCESS);
}
pmsg/pmsg_send.c
48.5.2. Получение сообщений
Функция mq_receive() удаляет из очереди, куда ссылается дескриптор mqdes, самое старое сообщение с наивысшим приоритетом, после чего возвращает это сообщение в буфер, на который указывает аргумент msg_ptr.
#include
ssize_t mq_receive(mqd_t
unsigned int *
При успешном завершении возвращает количество байтов в полученном сообщении; при ошибке возвращает -1
Вызывающий процесс использует аргумент msg_len, чтобы сообщить о том, сколько байтов доступно в буфере, на который указывает msg_ptr.
Вне зависимости от реального размера сообщения аргумент msg_len (и, как следствие, размер буфера, на который указывает msg_ptr) должен быть больше или равен атрибуту очереди mq_msgsize; в противном случае mq_receive() завершится ошибкой EMSGSIZE. Если мы не знаем значение данного атрибута, то можем его получить с помощью функции mq_getattr() (в приложении, состоящем из взаимодействующих процессов, обычно можно обойтись и без этой функции, поскольку параметр mq_msgsize, как правило, устанавливается заранее).
Если аргумент msg_prio не равен NULL, то приоритет полученного сообщения копируется по адресу, на который указывает msg_prio.
При пустой очереди функция mq_receive() либо блокируется, пока не станет доступным хотя бы одно сообщение, либо сразу же завершается ошибкой EAGAIN, если был установлен флаг O_NONBLOCK (мы не увидим символ конца файла при отсутствии записывающих процессов, как это происходит при использовании каналов).
Программа из листинге 48.5, предоставляет интерфейс командной строки к функции mq_receive(). Формат команд для этой программы представлен в функции usageError().
Следующая сессия командной строки демонстрирует использование программ из листингов 48.4 и 48.5. Вначале создадим очередь и отправим в нее несколько сообщений с разными приоритетами:
$ ./pmsg_create — cx /mq
$ ./pmsg_send /mq msg-a 5