Назначение переменных, описанных в программе:
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).
Прежде всего программа запрашивает, какую операцию нужно выполнить - послать или принять сообщение. Должно быть введено число, соответствующее требуемой операции; это число заносится в переменную 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 года (по Гринвичу).
Если указано, что требуется принять сообщение, начальное значение указателя 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 }