Provided by: manpages-ru-dev_4.19.0-7_all bug

ИМЯ

       msgrcv, msgsnd - операции с очередью сообщений System V

LIBRARY

       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). Эта проверка
          необходима для предотвращения помещения в  очередь  бесконечного  количества  сообщений
          нулевой  длины.  Хотя  такие сообщения не содержат данных, тем не менее, они потребляют
          (блокируют) память ядра.

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

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

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

       Аргумент 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 и 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.

       Реализация не накладывает существенных системных ограничений  на  максимальное  количество
       заголовков сообщений (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, "Использование: %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  <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 версии 3 ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩ или более позднюю, чтобы
       узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.

       Если вы обнаружите ошибки в переводе  этой  страницы  руководства,  пожалуйста,  отправьте
       электронное письмо на ⟨man-pages-ru-talks@lists.sourceforge.net⟩.