MSGOP(2) | System Calls Manual | MSGOP(2) |
msgrcv, msgsnd - операции с очередью сообщений System V
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() добавляет копию сообщения, указанного msgp, в очередь сообщений, идентификатор которой задаётся в msqid.
Если в очереди достаточно места, то msgsnd() сразу успешно завершается. Размер очереди управляется полем msg_qbytes в связанной структуре данных очереди сообщений. При создании очереди это поле инициализируется значением MSGMNB байт, но данное ограничение можно изменить с помощью msgctl(2). Очередь сообщений считается заполненной при одном из следующих условий:
Если в очереди недостаточно места, то по умолчанию msgsnd() блокирует выполнение до появления свободного места. Если в msgflg указан IPC_NOWAIT, то вызов вместо этого завершается с ошибкой EAGAIN.
Заблокированный вызов msgsnd() может завершиться ошибкой если:
Перед успешным завершением структура данных очереди сообщений будет обновлена следующим образом:
Системный вызов msgrcv() удаляет сообщение из очереди, указанной в msqid и помещает его в буфер, указанный в msgp.
Параметр msgsz задаёт максимальный размер (в байтах) элемента mtext структуры, находящейся по адресу, указанному в аргументе msgp. Если длина текста сообщения больше чем msgsz, то поведение зависит от наличия флага MSG_NOERROR в msgflg. Если MSG_NOERROR указан, то текст сообщения будет урезан (а урезанная часть потеряна); иначе сообщение не удаляется из очереди, а системный вызов возвращает -1 и присваивает errno значение E2BIG.
Если в msgflg (смотрите ниже ) не указан MSG_COPY, то в аргументе msgtyp указывается тип запрашиваемого сообщения:
Аргумент msgflg представляет собой битовую маску из комбинации нуля или более следующих флагов:
Если в очереди нет сообщения необходимого типа и в msgflg не указан IPC_NOWAIT, то вызывающий процесс будет заблокирован до тех пор, пока не произойдет одно из следующих событий:
Перед успешным завершением структура данных очереди сообщений будет обновлена следующим образом:
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:
msgrcv() can fail with the following errors:
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() влияют следующие системные ограничения на ресурсы очереди сообщений:
Реализация не накладывает существенных системных ограничений на максимальное количество заголовков сообщений (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 или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.
Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на man-pages-ru-talks@lists.sourceforge.net.
5 февраля 2023 г. | Linux man-pages 6.03 |