Назад |
Очередь сообщений представляет собой механизм передачи порций данных одинаковой длины. Каждая создаваемая очередь имеет уникальный ключ.
Создание объекта или доступ к нему производится при помощи функции msgget( ):
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget (key_t key, int flag);
Первый аргумент задает идентификатор очереди. Второй - flag - комбинация флагов, которая задает права доступа к объекту, а также то, следует ли создавать очередь сообщений или же использовать очередь, уже созданную другим процессом. Возможные флаги следующие:
MSG_R | 00400 | владелец может читать; |
MSG_W | 00200 | владелец может писать; |
(MSG_R>>3) | 00040 | пользователи, входящие в одну группу с владельцем (группа), могут читать; |
(MSG_R>>3) | 00020 | группа может писать; |
(MSG_R>>6) | 00004 | все остальные пользователи (остальные) могут читать; |
(MSG_R>>6) | 00002 | остальные могут писать; |
IPC_PRIVATE | создается объект, который может использоваться лишь данным процессом; | |
IPC_CREAT | создать объект, если он не существует; | |
IPC_EXCL | используется в сочетании с IPC_CREAT; если этот флаг выставлен, и объект с заданным ключом существует, то функция возвращает код ошибки. |
(При описании приведены также численные значения констант). Функция возвращает процессу идентификатор, используемый в дальнейшем для работы с объектом IPC. В случае возникновения ошибок msgget( ) возвращает значение -1.
Сообщение представляет собой массив байт, первые четыре из которых являются целым числом, содержащим тип сообщения. Следующие далее байты содержат данные сообщения. Если перед тем как использовать сообщение в программе, можно определить его максимальный размер, целесообразно использовать следующую структуру:
struct msg_struct { long msg_type; /* тип сообщения */ char msg_data [MAX_MSG__DATA]; /* данные сообщения */ };
Тип используется при выборе сообщения из очереди. Следует отметить, что операционная система накладывает ограничения на максимальный размер сообщений, количество сообщений в одной очереди и общее количество сообщений, записанное во все очереди. Соответствующие ограничения задаются константами MSGMAX, MSGNNB, MSGTQL в файле <sys/msg.h>.
Записать сообщение в очередь можно, используя функцию msgsnd( ):
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgsnd (int msgid, const void *ptr, size_t nbytes, int flag;
Здесь :
msgid | - идентификатор очереди, полученный при вызове msgget( ); |
ptr | - указатель на сообщение, записываемое в очередь; |
nbytes | - размер сообщения в байтах; |
flag | - либо 0, либо IPC_NOWAIT; в первом случае, если очередь полна, то msgsnd( ) ждет ее освобождения; во втором случае функция при полной очереди возвращается сразу с кодом -1. |
Получение сообщений из очереди производится вызовом функции msgrcv( ). Формат вызова функции следующий:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgrcv (int msgid, void *ptr, size_t nbytes, long type, int flag);
Здесь:
msgid | - идентификатор очереди, полученный при вызове msgget( ); |
ptr | - указатель на буфер для приема сообщения; |
nbytes | - размер буфера; |
type | - тип выбираемого из очереди сообщения; если значение этого параметра равно 0, из очереди выбирается первое по порядку сообщение; если type больше 0, из очереди выбирается первое сообщение, поле msg_type которого (см. определение msg_struct) содержит значение равное значению, хранящемуся в первых четырех байтах буфера приема сообщения; если же type меньше 0, будет выбрано сообщение, имеющее минимальное значение поля msg_type; |
flag | - либо 0, либо IPC_NOWAIT; в первом случае, если очередь пуста, то msgrcv() ждет прихода события; во втором случае функция при пустой очереди возвращается сразу с кодом -1. |
Для управления состоянием очереди сообщений используется системный вызов msgctl( ). Функция позволяет получить информацию о состоянии очереди, изменить права доступа процессов к ней или удалить объект. Ее прототип следующий:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgctl (int msgid, int cmd, struct msqid_ms *buf);
Здесь:
msgid | - идентификатор очереди, полученный при вызове msgget( ); |
cmd | - команда управления очередью; значения параметра определяются константами: IPC_STAT - получить состояние очереди, IPC_SET - установить параметры очереди, и IPC_RMID - удалить очередь сообщений; |
buf | - адрес структуры данных, используемой при выполнении команд, задаваемых параметром cmd. |
Ниже приводится пример двух программ, использующих очередь сообщений. Первая из них - клиент - вводит строку терминала. Если строка не нулевой длины, то она передается второй программе - серверу - через очередь сообщений. Сервер выводит полученную информацию на экран. Если же строка пуста, то передается сообщение об окончании работы. После чего обе программы завершаются.
Оба процесса используют файл заголовок "message.h".
#include <sys/types.h> #include <sys/ips.h> #include <sys/msg.h> #define MSQ_ID 2001 /* уникальный ключ очереди */ #define PERMS 00666 /* права доступа - все могут читать и писать */ #define MSG_TYPE_STRING 1 /* тип сообщения о том, что передана непустая строка */ #define MSG_TYPE_FINISH 2 /* тип сообщения о том, что пора завершать обмен */ #define MAX_STRING 120 /* максимальная длина строки */ typedef struct /* структура сообщения */ { int type; char string [MAX_STRING]; } message_t;
Код программы-клиента:
#include <stdio.h> #include <string.h> #include "message.h" void sys_err (char * msg) { puts (msg); exit (1); } int main () { int msqid; /* идентификатор очереди сообщений */ message_t msg; /* сообщение */ char s [MAX_STRING]; /* создание очереди */ if ( (msqid = msgget (MSQ_ID, 0)) < 0) sys_err ("client:can not get msg queue"); while (1) { scanf ("%s", s); /* ввод строки */ if (strlen (s) != 1) { msg.type = MSG_TYPE_STRING; strncpy (msg.string, s, MAX_STRING); } else { msg.type = MSG_TYPE_FINISH; }; /* посылка сообщения процессу-серверу */ if (msgsnd (msqid, &msg, sizeof (message_t), 0) != 0) sys_err ("client: message send error"); if (strlen (s) == 1) /* пустая строка - выход */ break; } exit (0); }
Код программы-сервера:
#include <stdio.h> #include <string.h> #include "message.h" void sys_err (char * msg) { puts (msg); exit (1); }; int main () { int msqid; message_t msg; char s [MAX_STRING]; /* создание очереди сообщений */ if ( (msqid = msgget (MSQ_ID, PERMS | IPC_CREAT) ) < 0) sys_err ("server: can not create msg queue"); while (1) { /* получение очередного сообщения */ if (msgrcv (msqid, &msg, sizeof (message_t), 0, 0) < 0) sys_err ("server: msg recive error"); if (msg.type == MSG_TYPE_STRING) /* печать строки */ printf ("%s", msg.string); if (msg.type == MSG_TYPE_FINISH) /* выход из цикла */ break; } /* удаление очереди сообщений */ if (msgctl (msqid, IPC_RMID, (struct msqid_ds *) 0) < 0) sys_err ("server: msq queue remove error"); exit (0); }