MSGOP(2)

НАИМЕНОВАНИЕ
msgrcv, msgsnd - операции с очередью сообщений System V

БИБЛИОТЕКА
Стандартная библиотека языка C (libc, -lc)

ОБЗОР
#include <sys/msg.h>

ssize_t msgrcv(size_t msgsz;
               int msqid, void msgp[msgsz], size_t msgsz, long msgtyp,
               int msgflg);

int msgsnd(size_t msgsz;
               int msqid, const void msgp[msgsz], size_t msgsz,
               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). Эта проверка необходима для предотвращения помещения в очередь бесконечного количества сообщений нулевой длины. Хотя такие сообщения не содержат данных, тем не менее, они потребляют (блокируют) память ядра.

Если в очереди недостаточно места, то по умолчанию msgsnd() блокирует выполнение до появления свободного места. Если в msgflg указан IPC_NOWAIT, то вызов вместо этого завершается с ошибкой EAGAIN.

Заблокированный вызов msgsnd() может завершиться ошибкой если:

•   очередь удалена (в этом случае системный вызов выдаст ошибку, определив errno в значение EIDRM;

•   a signal is caught, in which case the system call fails with errno set to EINTR; see signal(7). (msgsnd() is never automatically restarted after being interrupted by a signal handler, regardless of the setting of the SA_RESTART flag when establishing a signal handler.)

Перед успешным завершением структура данных очереди сообщений будет обновлена следующим образом:

•   Значение 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.

Аргумент msgflg представляет собой битовую маску из комбинации нуля или более следующих флагов:

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 байт.

Если в очереди нет сообщения необходимого типа и в msgflg не указан IPC_NOWAIT, то вызывающий процесс будет заблокирован до тех пор, пока не произойдет одно из следующих событий:

•   В очередь не будет помещено сообщение необходимого типа.

•   Очередь сообщений удалена из системы. В этом случае системный вызов возвращает ошибку и присваивает 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.

msgrcv() can fail with the following errors:

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 and MSG_COPY were specified in msgflg and the queue contains fewer than msgtyp messages.

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-2024.

Флаги MSG_EXCEPT и MSG_COPY есть только в Linux; их определения можно получить указав макрос тестирования свойств _GNU_SOURCE.

ИСТОРИЯ
POSIX.1-2001, SVr4.

The msgp argument is declared as struct msgbuf * in glibc 2.0 and 2.1. It is declared as void * in glibc 2.2 and later, as required by SUSv2 and SUSv3.

ПРИМЕЧАНИЯ
На работу системного вызова msgsnd() влияют следующие системные ограничения на ресурсы очереди сообщений:

MSGMAX
    Максимальный размер текста сообщения: по умолчанию он равен 8192 байтам (в Linux это ограничение можно прочитать и изменить через /proc/sys/kernel/msgmax).

MSGMNB
    Максимальное количество байт, которое может храниться в очереди сообщений (по умолчанию 16384 байт). В Linux это ограничение можно прочитать и изменить через /proc/sys/kernel/msgmnb. Привилегированный процесс (Linux: процесс с мандатом CAP_SYS_RESOURCE) может устанавливать размер очереди сообщений больше чем MSGMNB при помощи вызова msgctl() с операцией IPC_SET.

Реализация не накладывает существенных системных ограничений на максимальное количество заголовков сообщений (MSGTQL) и на количество байт в пуле сообщений (MSGPOOL).

ОШИБКИ
В 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, "Usage: %s [options]\n", prog_name);
        fprintf(stderr, "Options are:\n");
        fprintf(stderr, "-s        send message using msgsnd()\n");
        fprintf(stderr, "-r        read message using msgrcv()\n");
        fprintf(stderr, "-t        message type (default is 1)\n");
        fprintf(stderr, "-k        message queue key (default is 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), "a message at %s",
                 ctime(&t));

        if (msgsnd(qid, &msg, sizeof(msg.mtext),
                   IPC_NOWAIT) == -1)
        {
            perror("msgsnd error");
            exit(EXIT_FAILURE);
        }
        printf("sent: %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], "must use either -s or -r option\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 <aereiae@gmail.com>, Alexey <a.chepugov@gmail.com>, Azamat Hackimov <azamat.hackimov@gmail.com>, Dmitriy S. Seregin <dseregin@59.ru>, Dmitry Bolkhovskikh <d20052005@yandex.ru>, ITriskTI <ITriskTI@gmail.com>, Max Is <ismax799@gmail.com>, Yuri Kozlov <yuray@komyakino.ru>, Иван Павлов <pavia00@gmail.com> и Малянов Евгений Викторович <maljanow@outlook.com>

Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.

Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу списка рассылки русских переводчиков (<debian-l10n-russian@lists.debian.org>).