KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Уильям Стивенс - UNIX: взаимодействие процессов

Уильям Стивенс - UNIX: взаимодействие процессов

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Уильям Стивенс, "UNIX: взаимодействие процессов" бесплатно, без регистрации.
Перейти на страницу:

Значение аргумента len функции mq_receive должно быть по крайней мере не меньше максимального размера сообщения, которое может быть помещено в очередь, то есть значения поля mq_msgsize структуры mq_attr для этой очереди. Если len оказывается меньше этой величины, немедленно возвращается ошибка EMSGSIZE. 

ПРИМЕЧАНИЕ

Это означает, что большинству приложений, использующих очереди сообщений Posix, придется вызывать mq_getattr после открытия очереди для определения максимального размера сообщения, а затем выделять память под один или несколько буферов чтения этого размера. Требование, чтобы буфер был больше по размеру, чем максимально возможное сообщение, позволяет функции mq_receive не возвращать уведомление о том, что размер письма превышает объем буфера. Сравните это, например, с флагом MSG_NOERROR и ошибкой E2BIG для очередей сообщений System V (раздел 6.4) и флагом MSG_TRUNC для функции recvmsg, используемой с дейтаграммами UDP (раздел 13.5 [24]). 

Аргумент prio устанавливает приоритет сообщения для mq_send, его значение должно быть меньше MQ_PRIO_MAX. Если при вызове mq_receive priop является ненулевым указателем, в нем сохраняется приоритет возвращаемого сообщения. Если приложению не требуется использование различных приоритетов сообщений, можно указывать его равным нулю для mq_send и передавать mq_receive нулевой указатель в качестве последнего аргумента.

ПРИМЕЧАНИЕ

Разрешена передача сообщений нулевой длины. Это тот случай, когда важно не то, о чем говорится в стандарте (Posix.1), а то, о чем в нем не говорится: нигде не запрещена передача сообщений нулевой длины. Функция mq_receive возвращает количество байтов в сообщении (в случае успешного завершения работы) или –1 в случае возникновения ошибок, так что 0 обозначает сообщение нулевой длины. 

Очередям сообщений Posix и System V не хватает полезной функции: получатель не может определить отправителя сообщения. Эта информация могла бы пригодиться многим приложениям. К сожалению, большинство механизмов передачи сообщений IPC не позволяют определить отправителя сообщений. В разделе 15.5 мы расскажем, как эта возможность обеспечивается для дверей. В разделе 14.8 [24] описано, как эта возможность обеспечивается в BSD/OS для доменных сокетов Unix. В разделе 15.3.1 [21] описано, как SVR4 передает информацию об отправителе по каналу при передаче по нему дескриптора. В настоящее время методы BSD/OS широко используются, и хотя реализация SVR4 является частью стандарта Unix 98, она требует передачи дескриптора по каналу, что обычно является более дорогостоящей операцией, чем просто передача данных. Мы не можем предоставить отправителю возможность передать информацию о себе (например, эффективный идентификатор пользователя) в самом сообщении, поскольку мы не можем быть уверены, что эта информация окажется истинной. Хотя разрешения доступа к очереди сообщений определяют, имеет ли право отправитель помещать в нее сообщения, это все равно не дает однозначности. Существует возможность создавать одну очередь для каждого отправителя (о которой рассказывается в связи с очередями System V в разделе 6.8), но это плохо подходит для больших приложений. Наконец, если функции для работы с очередями сообщений реализованы как пользовательские функции (как мы показываем в разделе 5.8), а не как часть ядра, мы не можем доверять никакой информации об отправителе, передаваемой с сообщением, так как ее легко подделать. 

Пример: программа mqsend

В листинге 5.5 приведен текст программы, помещающей сообщение в очередь.

Листинг 5.5. Программа mqsend

//pxmsg/mqsend.c

1  #include "unpipc.h"

2  int

3  main(int argc, char **argv)

4  {

5   mqd_t mqd;

6   void *ptr;

7   size_t len;

8   uint_t prio;

9   if (argc != 4)

10   err_quit("usage: mqsend <name> <#bytes> <priority>");

11  len = atoi(argv[2]);

12  prio = atoi(argv[3]);

13  mqd = Mq_open(argv[1], O_WRONLY);

14  ptr = Calloc(len, sizeof (char));

15  Mq_send(mqd, ptr, len, prio);

16  exit(0);

17 }

И размер сообщения, и его приоритет являются обязательными аргументами командной строки. Буфер под сообщение выделяется функцией callос, которая инициализирует его нулем.

Пример: программа mqreceive

Программа в листинге 5.6 считывает сообщение из очереди.

Листинг 5.6. Программа mqreceive

//pxmsg/mqreceive.с

1  #include "unpipc.h"

2  int

3  main(int argc, char **argv)

4  {

5   int с flags;

6   mqd_t mqd;

7   ssize_t n;

8   uint_t prio;

9   void *buff;

10  struct mq_attr attr;

11  flags = O_RDONLY;

12  while ((c = Getopt(argc, argv, "n")) != –1) {

13   switch (c) {

14   case 'n':

15    flags |= O_NONBLOCK;

16    break;

17   }

18  }

19  if (optind != argc – 1)

20   err_quit("usage: mqreceive [ –n ] <name>");

21  mqd = Mq_open(argv[optind], flags);

22  Mq_getattr(mqd, &attr);

23  buff = Malloc(attr.mqjnsgsize);

24  n = Mq_receive(raqd, buff, attr.mq_msgsize, &prio);

25  printf("read %ld bytes, priority = %un", (long) n, prio);

26  exit(0);

27 }

Параметр -n запрещает блокировку

14-17 Параметр командной строки –n отключает блокировку. При этом программа возвращает сообщение об ошибке, если в очереди нет сообщений.

Открытие очереди и получение атрибутов

21-25 Мы открываем очередь и получаем ее атрибуты, вызвав mq_getattr. Нам обязательно нужно определить максимальный размер сообщения, потому что мы должны выделить буфер подходящего размера, чтобы вызвать mq_receive. Программа выводит размер считываемого сообщения и его приоритет.

ПРИМЕЧАНИЕ

Поскольку n имеет тип size_t и мы не знаем, int это или long, мы преобразуем эту величину к типу long и используем строку формата %ld. В 64-разрядной реализации int будет 32-разрядным целым, a long и size_t будут 64-разрядными целыми.

Воспользуемся обеими программами, чтобы проиллюстрировать использование поля приоритета.

solaris % mqcreate /test1

solaris % mqgetattr /test1        создаем очередь и смотрим на ее атрибуты

max #msgs = 128, max #bytes/msg = 1024, #currently on queue = 0

solaris % mqsend /test1 100 99999 отправка с некорректным значением приоритета

mq_send error: Invalid argument

solaris % mqsend /test1 100 6     100 байт, приоритет 6

solaris % mqsend /test1 50 18     50 байт, приоритет 18

solaris % mqsend /test1 33 18     33 байт, приоритет 18

solaris % mqreceive /test1

read 50 bytes, priority = 18         возвращается старейшее сообщение с

solaris % mqreceive /test1        наивысшим приоритетом

read 33 bytes, priority = 18

Solaris % mqreceive /test1

read 100 bytes, priority = 6

Solaris % mqreceive –n /test1     отключаем блокировку и убеждаемся, что очередь пуста

mq_receive error: Resource temporarily unavailable

Мы видим, что mq_receive действительно возвращает старейшее сообщение с наивысшим приоритетом. 

5.5. Ограничения очередей сообщений

Мы уже сталкивались с двумя ограничениями, устанавливаемыми для любой очереди в момент ее создания:

■ mq_maxmsg — максимальное количество сообщений в очереди;

■ mq_msgsize — максимальный размер сообщения.

Не существует каких-либо ограничений на эти значения, хотя в рассматриваемых реализациях необходимо наличие в файловой системе места для файла требуемого размера. Кроме того, ограничения на эти величины могут накладываться реализацией виртуальной памяти (см. упражнение 5.5).

Другие два ограничения определяются реализацией:

■ MQ_OPEN_MAX — максимальное количество очередей сообщений, которые могут быть одновременно открыты каким-либо процессом (Posix требует, чтобы эта величина была не меньше 8);

■ MQ_PRIO_MAX — максимальное значение приоритета плюс один (Posix требует, чтобы эта величина была не меньше 32).

Эти две константы часто определяются в заголовочном файле <unistd.h> и могут быть получены во время выполнения программы вызовом функции sysconf, как мы покажем далее.

Пример: программа mqsysconf

Программа в листинге 5.7 вызывает функцию sysconf и выводит два ограничения на очереди сообщений, определяемые реализацией.

Листинг 5.7. Получение ограничений очередей с помощью sysconf

//pxmsg/mqsysconf.с

1 #include "unpipc.h"

2 int

3 main(int argc, char **argv)

4 {

5  printf("MQ_OPEN_MAX = %ld, MQ_PRIO_MAX = %ldn",

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*