ИМЯ
msgrcv, msgsnd - операции с очередью сообщений System VLIBRARY
Standard C library ( libc, -lc)СИНТАКСИС
#include <sys/msg.h>
int msgsnd(int msqid, const void msgp[.msgsz], size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void msgp[.msgsz], size_t msgsz, long msgtyp, int msgflg);
ОПИСАНИЕ
Системные вызовы msgsnd() и msgrcv() используются для отправки и получения сообщений из очереди сообщений System V. Вызывающий процесс должен иметь права на запись в очередь сообщений, чтобы отправлять сообщения и права на чтение для получения сообщений. Аргумент msgp представляет собой указатель на структуру, определяемую вызывающим как:struct msgbuf { long mtype; /* тип сообщения, значение должно быть > 0 */ char mtext[1]; /* данные сообщения */ };
Поле mtext является массивом (или другой структурой), размер которого определяется msgsz — неотрицательным целым значением. Разрешены сообщения нулевой длины (т.е. без поля mtext). Поле mtype должно быть только положительным целым значением. Это значение используется процессом-получателем для выбора сообщения (см. описание msgrcv() далее).
msgsnd()
Системный вызов msgsnd() добавляет копию сообщения, указанного msgp, в очередь сообщений, идентификатор которой задаётся в msqid. Если в очереди достаточно места, то msgsnd() сразу успешно завершается. Размер очереди управляется полем msg_qbytes в связанной структуре данных очереди сообщений. При создании очереди это поле инициализируется значением MSGMNB байт, но данное ограничение можно изменить с помощью msgctl(2). Очередь сообщений считается заполненной при одном из следующих условий:- •
- Добавление нового сообщения привело бы к превышению общего количества байт очереди над максимальным количеством размером очереди (поле msg_qbytes).
- •
- Добавление другого сообщения привело бы к превышению общего количества сообщений очереди над максимальным количеством размером очереди (поле msg_qbytes). Эта проверка необходима для предотвращения помещения в очередь бесконечного количества сообщений нулевой длины. Хотя такие сообщения не содержат данных, тем не менее, они потребляют (блокируют) память ядра.
- •
- очередь удалена (в этом случае системный вызов выдаст ошибку, определив errno в значение EIDRM;
- •
- пойман сигнал; в этом случае системный вызов завершается с ошибкой и присваивает errno значение EINTR; см. signal(7). Вызов msgsnd() никогда не перезапускается автоматически после прерывания обработчиком сигнала, независимо от установки флага SA_RESTART при настройке обработчика сигнала.
- •
- Значение msg_lspid устанавливается равным идентификатору вызывающего процесса.
- •
- Значение msg_qnum увеличивается на 1.
- •
- Значение msg_stime присваивается значение текущего времени.
msgrcv()
Системный вызов msgrcv() удаляет сообщение из очереди, указанной в msqid и помещает его в буфер, указанный в msgp. Параметр msgsz задаёт максимальный размер (в байтах) элемента mtext структуры, находящейся по адресу, указанному в аргументе msgp. Если длина текста сообщения больше чем msgsz, то поведение зависит от наличия флага MSG_NOERROR в msgflg. Если MSG_NOERROR указан, то текст сообщения будет урезан (а урезанная часть потеряна); иначе сообщение не удаляется из очереди, а системный вызов возвращает -1 и присваивает errno значение E2BIG. Если в msgflg (смотрите ниже ) не указан MSG_COPY, то в аргументе msgtyp указывается тип запрашиваемого сообщения:- •
- Если msgtyp равно нулю, то читается первое сообщение в очереди.
- •
- Если msgtyp больше нуля, то из очереди читается первое сообщение с типом msgtyp (если только в msgflg не указан MSG_EXCEPT. В этом случае из очереди читается первое сообщение, тип которого не равен msgtyp).
- •
- Если msgtyp меньше нуля, то из очереди читается первое сообщение со значением, меньшим или равным абсолютному значению msgtyp.
- IPC_NOWAIT
- Немедленный возврат, если в очереди нет сообщений необходимого типа. При этом системный вызов возвращает ошибку, присваивая errno значение ENOMSG.
- MSG_COPY (начиная с Linux 3.8)
- Забирает копию сообщения без удаления из начальной позиции в очереди, заданной в msgtyp (сообщения нумеруются начиная с 0).
- Этот флаг должен указываться вместе с IPC_NOWAIT; в этом случае, если в заданной позиции сообщение отсутствует, то вызов завершается с ошибкой ENOMSG немедленно. Флаги MSG_COPY и MSG_EXCEPT не могут указываться вместе в msgflg, так как кардинально изменяют смысл msgtyp.
- Флаг MSG_COPY был добавлен для реализации способности ядра для контрольных точек/восстановления и доступен только, если ядро собрано с параметром CONFIG_CHECKPOINT_RESTORE.
- MSG_EXCEPT
- Используется, если msgtyp больше 0, для чтения первого сообщения в очереди с типом, отличным от msgtyp.
- MSG_NOERROR
- Используется для урезания текста сообщения, если его размер больше msgsz байт.
- •
- В очередь не будет помещено сообщение необходимого типа.
- •
- Очередь сообщений удалена из системы. В этом случае системный вызов возвращает ошибку и присваивает errno значение EIDRM.
- •
- Вызывающий процесс не получит сигнал, который должен обработать. В этом случае системный вызов возвращает ошибку и присваивает переменной errno значение EINTR. Вызов msgrcv() никогда не перезапускается автоматически после прерывания обработчиком сигнала, независимо от установки флага SA_RESTART при настройке обработчика сигнала.
- Значение msg_lrpid устанавливается равным идентификатору вызывающего процесса.
- Значение msg_qnum уменьшается на 1.
- Значение msg_rtime становится равным текущему времени.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
On success, msgsnd() returns 0 and msgrcv() returns the number of bytes actually copied into the mtext array. On failure, both functions return -1, and set errno to indicate the error.ОШИБКИ
msgsnd() can fail with the following errors:- EACCES
- Вызывающий процесс не имеет прав записи в очередь сообщений и не имеет мандата CAP_IPC_OWNER в пользовательском пространстве имён, которое управляет его пространством имён IPC.
- EAGAIN
- Сообщение не может быть отправлено, так как размер очереди превысит лимит, равный msg_qbytes, а в параметре msgflg установлен флаг IPC_NOWAIT.
- EFAULT
- Память с адресом, указанным msgp, недоступна.
- EIDRM
- Очередь сообщений была удалена.
- EINTR
- Процесс ждал свободного места в очереди и получил сигнал, который должен обработать.
- EINVAL
- Задано неправильное значение msqid, не положительное значение mtype или неправильное значение msgsz (меньше 0, или больше системного лимита, заданного MSGMAX).
- ENOMEM
- Недостаточно памяти в системе для копирования сообщения, указанного msgp.
- E2BIG
- Длина текста получаемого сообщения больше, чем msgsz, а в поле msgflg не установлен флаг MSG_NOERROR.
- EACCES
- Вызывающий процесс не имеет прав чтобы прочитать очереди сообщений и не имеет мандата CAP_IPC_OWNER в пространстве имён пользователя, который управляет его пространством имён IPC.
- EFAULT
- Память с адресом, указанным msgp, недоступна.
- EIDRM
- Процесс ждал приёма сообщения, и в это время очередь сообщений была удалена.
- EINTR
- Во время ожидания приёма сообщения процесс получил сигнал; см. signal(7).
- EINVAL
- Неверное значение msqid или msgsz меньше 0.
- EINVAL (начиная с Linux 3.14)
- В msgflg указан флаг MSG_COPY, но нет IPC_NOWAIT.
- EINVAL (начиная с Linux 3.14)
- В msgflg указаны MSG_COPY и MSG_EXCEPT.
- ENOMSG
- В очереди нет сообщения необходимого типа, а в параметре msgflg установлен флаг IPC_NOWAIT.
- ENOMSG
- Флаги IPC_NOWAIT и MSG_COPY указаны в msgflg, но в очереди содержится меньше msgtyp сообщений.
- ENOSYS (начиная с Linux 3.8)
- Both MSG_COPY and IPC_NOWAIT were specified in msgflg, and this kernel was configured without CONFIG_CHECKPOINT_RESTORE.
СТАНДАРТЫ
POSIX.1-2001, POSIX.1-2008, SVr4. Флаги MSG_EXCEPT и MSG_COPY есть только в Linux; их определения можно получить указав макрос тестирования свойств _GNU_SOURCE.ЗАМЕЧАНИЯ
Аргумент msgp в glibc 2.0 и 2.1 объявлен как struct msgbuf *. В glibc 2.2 и новее, в соответствии с SUSv2 и SUSv3, он объявлен как void *. На работу системного вызова msgsnd() влияют следующие системные ограничения на ресурсы очереди сообщений:- MSGMAX
- Максимальный размер текста сообщения: по умолчанию он равен 8192 байтам (в Linux это ограничение можно прочитать и изменить через /proc/sys/kernel/msgmax).
- MSGMNB
- Максимальное количество байт, которое может храниться в очереди сообщений (по умолчанию 16384 байт). В Linux это ограничение можно прочитать и изменить через /proc/sys/kernel/msgmnb. Привилегированный процесс (Linux: процесс с мандатом CAP_SYS_RESOURCE) может устанавливать размер очереди сообщений больше чем MSGMNB при помощи вызова msgctl() с операцией IPC_SET.
ДЕФЕКТЫ
В Linux 3.13 и старее, если msgrcv() был вызван с флагом MSG_COPY flag, но без IPC_NOWAIT, и очередь сообщений содержала менее msgtyp сообщений, то вызов блокировал выполнения до тех пор, пока следующее сообщение не записывалось в очередь. written to the queue. В этот момент вызов возвращал копию сообщения, независимо от того, что сообщение было в начальной позиции msgtyp. Этот дефект был исправлен в Linux 3.14. Указание обоих флагов MSG_COPY и MSC_EXCEPT в msgflg является логической ошибкой (так как для флагов по-разному интерпретируется msgtyp). В Linux 3.13 и старее эта ошибка не определялась msgrcv(). Этот дефект был исправлен в Linux 3.14.ПРИМЕРЫ
Представленная ниже программа показывает использование msgsnd() и msgrcv(). В первый раз программа запускается с параметром -s для отправки сообщения, а в второй — с параметром -r для получения сообщения. Пример сеанса работы с программой:$ ./a.out -s отправка: дата сообщения Wed Mar 4 16:25:45 2015 $ ./a.out -r приём: дата сообщения Wed Mar 4 16:25:45 2015
Исходный код программы
#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/msg.h> #include <time.h> #include <unistd.h> struct msgbuf { long mtype; char mtext[80]; }; static void usage(char *prog_name, char *msg) { if (msg != NULL) fputs(msg, stderr); fprintf(stderr, "Использование: %s [параметры]\n", prog_name); fprintf(stderr, "Параметры:\n"); fprintf(stderr, "-s отправить сообщение с помощью msgsnd()\n"); fprintf(stderr, "-r прочитать сообщение с помощью msgrcv()\n"); fprintf(stderr, "-t тип сообщения (по умолчанию 1)\n"); fprintf(stderr, "-k ключ очереди сообщения (по умолчанию 1234)\n"); exit(EXIT_FAILURE); } static void send_msg(int qid, int msgtype) { time_t t; struct msgbuf msg; msg.mtype = msgtype; time(&t); snprintf(msg.mtext, sizeof(msg.mtext), "дата сообщения %s", ctime(&t)); if (msgsnd(qid, &msg, sizeof(msg.mtext), IPC_NOWAIT) == -1) { perror("msgsnd error"); exit(EXIT_FAILURE); } printf("отправка: %s\n", msg.mtext); } static void get_msg(int qid, int msgtype) { struct msgbuf msg; if (msgrcv(qid, &msg, sizeof(msg.mtext), msgtype, MSG_NOERROR | IPC_NOWAIT) == -1) { if (errno != ENOMSG) { perror("msgrcv"); exit(EXIT_FAILURE); } printf("No message available for msgrcv()\n"); } else { printf("message received: %s\n", msg.mtext); } } int main(int argc, char *argv[]) { int qid, opt; int mode = 0; /* 1 = send, 2 = receive */ int msgtype = 1; int msgkey = 1234; while ((opt = getopt(argc, argv, "srt:k:")) != -1) { switch (opt) { case 's': mode = 1; break; case 'r': mode = 2; break; case 't': msgtype = atoi(optarg); if (msgtype <= 0) usage(argv[0], "-t option must be greater than 0\n"); break; case 'k': msgkey = atoi(optarg); break; default: usage(argv[0], "Unrecognized option\n"); } } if (mode == 0) usage(argv[0], "нужно указать параметр -s или -r\n"); qid = msgget(msgkey, IPC_CREAT | 0666); if (qid == -1) { perror("msgget"); exit(EXIT_FAILURE); } if (mode == 2) get_msg(qid, msgtype); else send_msg(qid, msgtype); exit(EXIT_SUCCESS); }
СМ. ТАКЖЕ
msgctl(2), msgget(2), capabilities(7), mq_overview(7), sysvipc(7)ПЕРЕВОД
Русский перевод этой страницы руководства был сделан aereiae <[email protected]>, Alexey <[email protected]>, Azamat Hackimov <[email protected]>, Dmitriy S. Seregin <[email protected]>, Dmitry Bolkhovskikh <[email protected]>, ITriskTI <[email protected]>, Max Is <[email protected]>, Yuri Kozlov <[email protected]>, Иван Павлов <[email protected]> и Малянов Евгений Викторович <[email protected]> Этот перевод является бесплатной документацией; прочитайте Стандартную общественную лицензию GNU версии 3 или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ. Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на [email protected]5 февраля 2023 г. | Linux man-pages 6.03 |