Руководство программиста для Linux


Очереди сообщений - часть 6


Конечно, первый аргумент определяет очередь, из которой будет взято сообщение (должен быть возвращен сделанным предварительно вызовом msgget). Второй аргумент (msgp) представляет собой адрес буфера, куда будет положено изъятое сообщение. Третий аргумент, msgsz, ограничивает размер структуры-буфера без учета длины элемента mtype.

Еще раз повторимся, это может быть легко вычислено: msgsz = sizeof(struct mymsgbuf) - sizeof(long);

Четвертый аргумент, mtype - это тип сообщения, изымаемого из очереди. Ядро будет искать в очереди наиболее старое сообщение такого типа и вернет его копию по адресу, указанному аргументом msgp. Существует один особый случай: если mtype = 0, то будет возвращено наиболее старое сообщение, независимо от типа.

Если IPC_NOWAIT был послан флагом, и нет ни одного удовлетворительного сообщения, msgrcv вернет вызывающему процессу ENOMSG. В противном случае вызывающий процесс блокируется, пока в очередь не прибудет сообщение, соответствующее параметрам msgrcv(). Если, пока клиент ждет сообщения, очередь удаляется, то ему возвращается EIDRM. EINTR возвращается, если сигнал поступил, пока процесс находился на промежуточной стадии между ожиданием и блокировкой.

Давайте рассмотрим функцию-переходник для изъятия сообщения из нашей очереди. int read_message( int qid, long type, struct mymsgbuf *qbuf ) { int result, length; /* Длина есть в точности размер структуры минус sizeof(mtype) */ length = sizeof(struct mymsgbuf) - sizeof(long); if((result = msgrcv( qid, qbuf, length, type, 0 )) == -1) { return(-1); } return(result); }

После успешного изъятия сообщения удаляется из очереди и его ярлык.

Бит MSG_NOERROR в msgflg предоставляет некоторые дополнительные возможности. Если физическая длина сообщения больше, чем msgsz, и MSG_NOERROR установлен, то сообщение обрезается и возвращается только msgsz байт. Нормальный же msgrcv() возвращает -1 (E2BIG), и сообщение остается в очереди до последующих запросов. Такое поведение можно использовать для создания другой оберточной функции, которая позволит нам "подглядывать" внутрь очереди, чтобы узнать, пришло ли сообщение, удовлетворяющее нашему запросу. int peek_message( int qid, long type ) { int result, length; if((result = msgrcv( qid, NULL, 0, type, IPC_NOWAIT )) == -1) { if(errno == E2BIG) return(TRUE); } return(FALSE); }




Начало  Назад  Вперед