| |
Назначение переменных, описанных в программе:
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 }
Закладки на сайте Проследить за страницей |
Created 1996-2024 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |