/* Создаем очередь или присоединяемся к уже существующей */
if ((id = msgget(key, IPC_CREAT | 0660)) == -1) {
printf('Ошибка при создании очереди
');
exit(1);
}
/* Заполняем сообщение */
msg.type = 1; /* тип сообщения,
должен быть положительным! */
msg.op_.type = 0; /* тип операции */
msg.l_op = 6;
msg.r_op = 5;
/* определяем длину сообщения - 4 байта */
length = sizeof(struct my_buf) - sizeof(long);
if ((res = msgsnd(id, &buf, length, 0)) == -1) {
printf('Ошибка при постановке сообщения в очередь
');
exit(1);
}
}
После запуска этой программы запустите программу ipcs и посмотрите на статус только что отправленного сообщения. Теперь напишем программу, которая получит это сообщение.
26.5.4. Получение сообщений очереди
Для получения сообщения используется системный вызов msgrcv():
int msgrcv(int msqid, struct msgbuf *msgp, int msgsz,
long mtype, int msgflg);
Первый аргумент определяет очередь, из которой нужно получить сообщение. Второй аргумент — это адрес буфера, в который будет записано сообщение. Третий аргумент — это ограничитель длины сообщения. Четвертый аргумент — это тип сообщения. Ядро будет искать в очереди наиболее старое сообщение данного типа и вернет его копию. Если mtype=0, то ядро вернет самое старое сообщение независимо от типа.
После успешного получения сообщения оно удаляется из очереди.
В случае успеха вызов msqrcv() возвращает число байтов, скопированных в буфер, или -1 в случае ошибки. Переменная errno устанавливается следующим образом:
♦ E2BIG — длина сообщения больше, чем ограничитель msgsz;
♦ EACCESS — у вас недостаточно прав;
♦ EFAULT — недоступен адрес буфера;
♦ EIDRM — очередь уничтожена ядром;
♦ EINTR — операция прервана поступившим сигналом;
♦ EINVAL — ошибка в аргументах, например, отрицательный размер сообщения или неверный номер очереди;
♦ ENOMSG — нет сообщения, удовлетворяющего условию. Посылается, если установлен флаг IPC_NOWAIT, в противном случае процесс будет ждать нужного сообщения.
Последний аргумент предоставляет дополнительные возможности по работе с сообщениями. Если установлен бит MSG_NOERROR в msgflg, то если размер сообщения больше, чем msgsz, оно будет обрезано и вы получите только msgsz байтов. Если флаг MSG_NOERROR не устанавливать, вы получите ошибку E2BIG.
Следующий код получает сообщение из очереди:
int id; /* ID очереди */
int res, length; /* результат операции и длина */
struct my_buf buf; /* буфер */
int type = 1; /* тип сообщения */
length = sizeof(struct my_buf) — sizeof(long);
if ((res =
msgrcv(id, &buf, length, type, 0)) == -1) {
printf('Ошибка!');
/* можно проанализировать ошибку */
if (errno==E2BIG) printf('Сообщение слишком большое
');
if (errno==EACCESS) printf('Heт доступа
');
/* и т.д. */
exit(1);
}
26.5.5. Проверка наличия сообщения в очереди
Наверное, вы не хотите, чтобы ваша программа ждала, пока в очереди появится нужное сообщение. Используя особенности системного вызова msgrcv(), можно написать код проверки наличия сообщения определенного типа в очереди. Напишем функцию msg_exists(), которая будет возвращать TRUE, если сообщение есть в очереди, или FALSE, если сообщения в очереди нет.
int msg_exists(int id, long type) {
int res;
if ((result = msgrcv(id, NULL, 0, type, IPC_NOWAIT)) == -1) {
if (errno == E2BIG)
return(TRUE);
}
return(FALSE);
}
В вызове msgrcv() отсутствует адрес буфера и длина сообщения. Этим мы специально провоцируем ошибку, а вызов IPC_NOWAIT отказывает от блокировки процесса. Мы проверяем errno; если он равен E2BIG, значит, сообщение есть в очереди. Ошибка E2BIG порождается потому, что мы установили размер сообщения равным 0.
26.5.6. Тотальный контроль