The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Каталог документации / Раздел "Документация для Linux" / Оглавление документа
next up previous contents index
Next: Семафоры Up: Операции над очередями сообщений Previous: Прием сообщений   Contents   Index

Программа-пример

Назначение переменных, описанных в программе:

sndbuf

Используется в качестве буфера, содержащего посылаемое сообщение (строка 12); шаблон при описании этой переменной - структура данных msgbufl (строки 9-12). Структура msgbufl является почти точной копией структуры msgbuf, описание которой находится во включаемом файле <sys/msg.h>. Единственное различие состоит в том, что длина символьного массива в msgbufl равна максимально допустимому размеру сообщения для данной конфигурации (MSGMAX), в то время как в msgbuf она устанавливается равной единице, чтобы отвечать требованиям компилятора. По этой причине нельзя использовать в пользовательской программе описание msgbuf непосредственно, то есть пользователь должен сам определять поля данной структуры.

rcvbuf

Используется в качестве буфера, содержащего принимаемое сообщение (строка 12); шаблон при описании этой переменной - структура данных msgbufl (строки 9-12).

i

Используется как счетчик символов при вводе с клавиатуры и занесении в массив, а также отслеживает длину сообщения при выполнении системного вызова msgsnd(); кроме того, используется как счетчик при выводе принятого сообщения после выполнения системного вызова msgrcv().

c

Содержит символ, возвращаемый функцией getchar() (строка 45).

flag

При выполнении системного вызова msgsnd() содержит значение, определяющее, нужен ли флаг IPC_NOWAIT (строка 55).

flags

При выполнении системного вызова msgrcv() содержит значение, определяющее комбинацию флагов IPC_NOWAIT и MSG_NOERROR (строка 103).

choice

Содержит признак, определяющий выбранную операцию - посылка или прием сообщения (строка 27).

Отметим, что в программе структура данных msqid_ds снабжается указателем на нее (строка 19), указатель соответствующим образом инициализируется (строка 20); это позволяет следить за полями ассоциированной структуры данных, которые могут измениться в результате операций над сообщениями. При помощи системного вызова msgctl() (действие IPC_STAT) программа получает значения полей ассоциированной структуры данных и выводит их (строки 74-82 и 145-152).

Прежде всего программа запрашивает, какую операцию нужно выполнить - послать или принять сообщение. Должно быть введено число, соответствующее требуемой операции; это число заносится в переменную choice (строки 21-27).

Если выбрана операция посылки сообщения, указатель msgp инициализируется адресом структуры данных sndbuf (строка 30). После этого запрашивается идентификатор очереди сообщений, в которую должно быть послано сообщение; идентификатор заносится в переменную msqid (строки 31-34). Затем должен быть введен тип сообщения; он заносится в поле mtype структуры данных, указываемой значением msgp (строка 34).

После этого программа приглашает ввести с клавиатуры текст посылаемого сообщения и выполняет цикл, в котором символы читаются и заносятся в массив mtext структуры данных (строки 43-46). Ввод продолжается до тех пор, пока не будет обнаружен признак конца файла; для функции getchar() таким признаком является символ CTRL+D, непосредственно следующий за символом возврата каретки. После того как признак конца обнаружен, определяется размер сообщения (строки 47, 48) - он на единицу больше значения счетчика i, поскольку элементы массива, в который заносится сообщение, нумеруются с нуля. Следует помнить, что сообщение будет содержать заключительные символы и, следовательно, будет казаться, что сообщение на три символа короче, чем указывает аргумент msgsz.

Чтобы обеспечить пользователю обратную связь, текст сообщения, содержащийся в массиве mtext структуры sndbuf, немедленно выводится (строки 49-51).

Следующее, и последнее, действие заключается в определении, должен ли быть установлен флаг IPC_NOWAIT. Чтобы выяснить это, программа предлагает ввести 1, если флаг установить нужно, или любое другое число, если не нужно (строки 52-59). Введенное значение заносится в переменную flag. Если введена единица, аргумент msgflg полагается равным IPC_NOWAIT, в противном случае msgflg устанавливается равным нулю.

После этого выполняется системный вызов msgsnd() (строка 63). Если вызов завершается неудачей, выводится сообщение об ошибке, а также ее код (строки 64-66). Если вызов завершается успешно, печатается возвращенное им значение, которое должно быть равно нулю (строки 69-71).

При каждой успешной посылке сообщения обновляются три поля ассоциированной структуры данных. Изменения можно описать следующим образом:

msg_qnum

Определяет общее число сообщений в очереди; в результате выполнения операции увеличивается на единицу.

msg_lspid

Содержит идентификатор процесса, который последним послал сообщение; полю присваивается соответствующий идентификатор.

msg_stime

Содержит время последней посылки сообщения, время измеряется в секундах, начиная с 00:00:00 1 января 1970 года (по Гринвичу).

После каждой успешной операции посылки сообщения значения этих полей выводятся (строки 76-82)

Если указано, что требуется принять сообщение, начальное значение указателя msgp устанавливается равным адресу структуры данных rcvbuf (строка 87).

Запрашивается код требуемой комбинации флагов, который заносится в переменную flags (строки 94-103). Переменная msgflg устанавливается в сответствии с выбранной комбинацией (строки 104- 119).

В заключение запрашивается, сколько байт нужно принять; указанное значение заносится в переменную msgsz (строки 120-123).

После этого выполняется системный вызов msgrcv() (строка 130) Если вызов завершается неудачей, выводится сообщение об ошибке, а также ее код (строки 131-133). Если вызов завершается успешно, программа сообщает об этом, а также выводит размер и текст сообщения (строки 135-144).

При каждом успешном приеме сообщения обновляются три поля ассоциированной структуры данных. Изменения можно описать следующим образом:

msg_qnum

Определяет общее число сообщений в очереди; в результате выполнения операции уменьшается на единицу.

msg_lrpid

Содержит идентификатор процесса, который последним получил сообщение; полю присваивается соответствующий идентификатор.

msg_rtime

Содержит время последнего получения сообщения, время измеряется в секундах, начиная с 00:00:00 1 января 1970 года (по Гринвичу).

Далее следует текст программы.
   1 /* Программа иллюстрирует
   2    возможности системных вызовов msgsnd() и msgrcv()
   3    (операции над очередями сообщений) */

   4 #include <stdio.h>
   5 #include <sys/types.h>
   6 #include <sys/ipc.h>
   7 #include <sys/msg.h>

   8 #define MAXTEXTSIZE 8192

   9 struct msgbufl {
  10   long mtype;
  11   char mtext [MAXTEXTSIZE];
  12 } sndbuf, rcvbuf, *msgp;

  13 main ()
  14 {
  15   extern int errno;
  16   int flag, flags, choice, rtrn, i, c;
  17   int rtrn, msqid, msgsz, msgflg;
  18   long msgtyp;
  19   struct msqid_ds msqid_ds, *buf;
  20   buf = &msqid_ds;

  21   /* Выбрать требуемую операцию */
  22   printf ("\nВведите код, соответствующий ");
  23   printf ("посылке или приему сообщения:\n");
  24   printf ("  Послать = 1\n");
  25   printf ("  Принять = 2\n");
  26   printf ("  Выбор   = ");
  27   scanf ("%d", &choice);

  28   if (choice == 1) {
  29     /* Послать сообщение */
  30     msgp = &sndbuf; /* Указатель на структуру */

  31     printf ("\nВведите идентификатор ");
  32     printf ("очереди сообщений,\n");
  33     printf ("в которую посылается сообщение: ");
  34     scanf ("%d", &msqid);

  35     /* Установить тип сообщения */
  36     printf ("\nВведите положительное число - ");
  37     printf ("тип сообщения: ");
  38     scanf ("%d", &msgp->mtype);

  39     /* Ввести посылаемое сообщение */
  40     printf ("\nВведите сообщение: \n");

  41     /* Управляющая последовательность CTRL+D
  42        завершает ввод сообщения */

  43     /* Прочитать символы сообщения
  44        и поместить их в массив mtext */
  45     for (i = 0; ((c = getchar ()) != EOF); i++)
  46       sndbuf.mtext [i] = c;

  47     /* Определить размер сообщения */
  48     msgsz = i + 1;

  49     /* Выдать текст посылаемого сообщения */
  50     for (i = 0; i < msgsz; i++)
  51       putchar (sndbuf.mtext [i]);

  52     /* Установить флаг IPC_NOWAIT, если это нужно */
  53     printf ("\nВведите 1, если хотите установить ");
  54     printf ("флаг IPC_NOWAIT: ");
  55     scanf ("%d", &flag);
  56     if (flag == 1)
  57       msgflg = IPC_NOWAIT;
  58     else
  59       msgflg = 0;

  60     /* Проверить флаг */
  61     printf ("\nФлаг = 0%o\n", msgflg);

  62     /* Послать сообщение */
  63     rtrn = msgsnd (msqid, msgp, msgsz, msgflg);
  64     if (rtrn == -1) {
  65       printf ("\nmsgsnd завершился неудачей!\n");
  66       printf ("Код ошибки = %d\n", errno);
  67     }
  68     else {
  69       /* Вывести результат; при успешном
  70          завершении он должен равняться нулю */
  71       printf ("\nРезультат = %d\n", rtrn);

  72       /* Вывести размер сообщения */
  73       printf ("\nРазмер сообщения = %d\n", msgsz);

  74       /* Опрос измененной структуры данных */
  75       msgctl (msqid, IPC_STAT, buf);

  76       /* Вывести изменившиеся поля */
  77       printf ("Число сообщений в очереди = %d\n",
  78               buf->msg_qnum);
  79       printf ("Ид-р последнего отправителя = %d\n",
  80               buf->msg_lspid);
  81       printf ("Время последнего отправления = %d\n",
  82               buf->msg_stime);
  83     }
  84   }

  85   if (choice == 2) {
  86     /* Принять сообщение */
  87     msgp = &rcvbuf;

  88     /* Определить нужную очередь сообщений */
  89     printf ("\nВведите ид-р очереди сообщений: ");
  90     scanf ("%d", &msqid);

  91     /* Определить тип сообщения */
  92     printf ("\nВведите тип сообщения: ");
  93     scanf ("%d", &msgtyp);

  94     /* Сформировать управляющие флаги
  95        для требуемых действий */
  96     printf ("\nВведите код, соответствущий ");
  97     printf ("нужной комбинации флагов:\n");
  98     printf ("  Нет флагов               = 0\n");
  99     printf ("  MSG_NOERROR              = 1\n");
 100     printf ("  IPC_NOWAIT               = 2\n");
 101     printf ("  MSG_NOERROR и IPC_NOWAIT = 3\n");
 102     printf ("  Выбор                    = ");
 103     scanf ("%d", &flags);

 104     switch (flags) {
 105       /* Установить msgflg как побитное ИЛИ
 106          соответствующих констант */
 107       case 0:
 108         msgflg = 0;
 109         break;
 110       case 1:
 111         msgflg = MSG_NOERROR;
 112         break;
 113       case 2:
 114         msgflg = IPC_NOWAIT;
 115         break;
 116       case 3:
 117         msgflg = MSG_NOERROR | IPC_NOWAIT;
 118         break;
 119     }

 120     /* Определить, какое число байт принять */
 121     printf ("\nВведите число байт, которое ");
 122     printf ("нужно принять (msgsz): ");
 123     scanf ("%d", &msgsz);

 124     /* Проверить значение аргументов */
 125     printf ("\nИдентификатор msqid = %d\n", msqid);
 126     printf ("Тип сообщения = %d\n", msgtyp);
 127     printf ("Число байт = %d\n", msgsz);
 128     printf ("Флаги = %o\n", msgflg);

 129     /* Вызвать msgrcv для приема сообщения */
 130     rtrn = msgrcv (msqid, msgp, msgsz, msgtyp, msgflg);

 131     if (rtrn == -1) {
 132       printf ("\nmsgrcv завершился неудачей!\n");
 133       printf ("Код oшибки = %d\n", errno);
 134     }
 135     else {
 136       printf ("\nmsgrcv завершился успешно,\n");
 137       printf ("идентификатор очереди = %d\n", msqid);

 138         /* Напечатать число принятых байт,
 139            оно равно возвращаемому значению */
 140         printf ("Принято байт: %d\n", rtrn);

 141         /* Распечатать принятое сообщение */
 142         for (i = 0; i < rtrn; i++)
 143           putchar (rcvbuf.mtext [i]);
 144     }

 145     /* Опрос ассоциированной структуры данных */
 146     msgctl (msqid, IPC_STAT, buf);

 147     printf ("\nЧисло сообщений в очереди = %d\n",
 148             buf->msg_qnum);
 149     printf ("Ид-р последнего получателя = %d\n",
 150             buf->msg_lrpid);
 151     printf ("Время последнего получения = %d\n",
 152             buf->msg_rtime);
 153   }

 154   exit (0);
 155 }



Alex Otwagin 2002-12-16



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру