Скачиваний:
90
Добавлен:
12.05.2015
Размер:
913.92 Кб
Скачать

18.4. Функция msgrcv

Сообщение может быть считано из очереди с помощью функции msgrcv.

#include <sys/msg.h>

int msgrcv (int msqid, void *ptr, size_t length, long type, int flag);

/* возвращает количество данных в сообщении, -1 – в случае ошибки */

Аргумент ptrуказывает, куда следует помещать принимаемые данные. Как и дляmsgsnd, он указывает на поле данных типаlong, которое непосредственно предшествует полезным данным.

Аргумент lengthзадает размер относящейся к полезным данным части буфера, на который указываетptr. Это максимальное количество данных, которое может быть возвращено функцией. Поле типаlongне входит в эту длину.

Аргумент typeопределяет тип сообщения, которое нужно считать из очереди:

  • если значение typeравно 0, возвращается первое сообщение в очереди (то есть при указании типа 0 возвращается старейшее сообщение);

  • если тип больше нуля, возвращается первое сообщение, тип которого равен указанному;

  • если тип меньше нуля, возвращается первое сообщение с наименьшим типом, значение которого меньше либо равно модулю аргумента type.

Рассмотрим пример очереди сообщений, изображенный на рис. 17.1. В этой очереди имеются три сообщения:

  • первое сообщение имеет тип 100 и длину 1;

  • второе сообщение имеет тип 200 и длину 2;

  • третье сообщение имеет тип 300 и длину 3.

Таблица 17.1 показывает, какое сообщение будет возвращено при различных значениях аргумента type.

Таблица 17.1

Возвращаемое значение в зависимости от аргумента type

type

Тип возвращаемого сообщения

0

100

100

100

200

200

300

300

-100

100

-200

100

-300

100

Аргумент flagуказывает, что делать, если в очереди нет сообщения с запрошенным типом. Если установлен битIPC_NOWAIT, происходит немедленный возврат из функцииmsgrcvс кодом ошибкиENOMSG. В противном случае вызвавший процесс блокируется до тех пор, пока не произойдет одно из следующих событий:

  • появится сообщение с запрошенным типом;

  • очередь с идентификатором msqidбудет удалена из системы (в этом случае будет возвращена ошибка с кодомEIDRM);

  • вызвавший поток будет прерван перехватываемым сигналом (в этом случае возвращается ошибка EINTR).

Если установлен бит MSG_EXCEPT, то мы прочитаем первое сообщение из очереди, тип которого не равенtype. Этот бит используется в том случае, когда при вызове функцииmsgrcvв аргументеtypeпередается положительное значение.

В аргументе flagможно указать дополнительный битMSG_NOERROR. При установке этого бита данные, превышающие размер буфера (аргументlength), будут просто обрезаться до его размера без возвращения кода ошибки. Если этот бит не установить, то при превышении сообщением размера приемного буфера будет возвращена ошибкаE2BIG.

В случае успешного завершения работы msgrcvвозвращает количество байтов в принятом сообщении. Оно не включает байты, нужные для хранения типа сообщения (long), который также возвращается через указательptr.

18.5. Функция msgctl

Функция msgctlпозволяет управлять очередями сообщений.

#include <sys/msg.h>

int msgctl (int msqid, int cmd, struct msqid_ds *buff);

/* возвращает 0 в случае успешного завершения, -1 – в случае ошибки */

Команд (аргумент cmd) может быть три:

  • IPC_RMID– удаление очереди с идентификаторомmsqidиз системы. Все сообщения, имеющиеся в этой очереди, будут утеряны. Для этой команды третий аргумент функции игнорируется;

  • IPC_SET– установка значений четырех полей структурыmsqid_dsданной очереди равными значениям соответствующих полей структуры, на которую указывает аргументbuff:msg_perm.uid,msg_perm.gid,msg_perm.mode,msg_qbytes;

  • IPC_STAT– возвращает вызвавшему процессу (через аргументbuff) текущее содержимое структурыmsqid_dsдля указанной очереди.

Пример. Программа влистинге 17.1создает очередь сообщений, помещает в нее сообщение с 1 байтом информации, вызывает функциюmsgctlс командойIPC_STAT, выполняет командуipcs, используя функциюsystem, а затем удаляет очередь, вызвав функциюmsgctlс командойIPC_RMID.

Листинг 17.1. Пример использования функции msgctl

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

#include <sys/stat.h>

#include <sys/msg.h>

#define MSG_R S_IRUSR

#define MSG_W S_IWUSR

#define SVMSG_MODE (MSG_R | MSG_W | MSG_R>>3 | MSG_R>>6)

struct msgbuf

{

long int mtype; /* тип сообщения, должен быть > 0 */

char mtext[1]; /* данные */

};

int main(int argc, char **argv)

{

int msqid;

struct msqid_ds info;

struct msgbuf buf;

if ((msqid = msgget(IPC_PRIVATE, SVMSG_MODE | IPC_CREAT)) == -1)

{

fprintf(stderr, "Ошибка вызова функции msgget: %s\n", strerror(errno));

exit(1);

}

buf.mtype = 1;

buf.mtext[0] = 1;

if (msgsnd(msqid, &buf, 1, 0) == -1)

{

fprintf(stderr, "Ошибка вызова функции msgsnd: %s\n", strerror(errno));

exit(1);

}

if (msgctl(msqid, IPC_STAT, &info) == -1)

{

fprintf(stderr, "Ошибка вызова функции msgctl(IPC_STAT): %s\n",

strerror(errno));

exit(1);

}

printf("read-write: %03o, cbytes = %lu, qnum = %lu, qbytes = %lu\n",

info.msg_perm.mode & 0777, (unsigned long) info.msg_cbytes,

(unsigned long) info.msg_qnum, (unsigned long) info.msg_qbytes);

system("ipcs -q");

if(msgctl(msqid, IPC_RMID, NULL) == -1)

{

fprintf(stderr, "Ошибка вызова функции msgctl(IPC_RMID): %s\n",

strerror(errno));

exit(1);

}

exit(0);

}

Вообще говоря, для получения доступа к очереди сообщений System V вовсе не обязательно вызывать функцию msgget: все, что нужно, – это знать идентификатор очереди сообщений, который легко получить с помощью командыipcs, и, конечно, иметь необходимые права доступа к очереди сообщений.

Соседние файлы в папке Chapter.4