Пример: необязательные данные
Пример: необязательные данные
Существуют три способа задания необязательных данных в файле XDR, примеры для всех приведены в листинге 16.17.
Листинг 16.17. Файл спецификации XDR, иллюстрирующий способы задания необязательных данных
//sunrpc/xdr1/opt1.x
1 union optlong switch (bool flag) {
2 case TRUE:
3 long val;
4 case FALSE:
5 void;
6 };
7 struct args {
8 optlong arg1; /* объединение с булевским дискриминантом */
9 long arg2<1>; /* массив переменной длины с одним элементом */
10 long *arg3; /* указатель */
11 };
Объявление объединения с булевским дискриминантом
1-8 Мы определяем объединение с ветвями FALSE и TRUE и структуру этого типа. Если флаг дискриминанта TRUE, за ним следует значение типа long; в противном случае за ним ничего не следует. После кодирования библиотекой XDR это объединение будет закодировано как:
? 4 байта флага со значением 1 (TRUE) и 4 байта целочисленного значения либо
? 4 байта флага со значением 0 (FALSE).
Объявление массива переменной длины
9 Если мы указываем массив переменной длины с одним возможным элементом, он будет передан как:
? 4 байта со значением 1 и 4 байта значения либо
? 4 байта со значением 0.
Объявление указателя XDR
10 Новый способ определения необязательных данных заключается в объявлении указателя. Он будет закодирован как:
? 4 байта со значением 1 и 4 байта значения либо
? 4 байта со значением 0
в зависимости от значения соответствующего указателя при кодировании данных. Если указатель ненулевой, используется первый вариант кодирования. Если указатель нулевой, получится второй вариант. Это удобный способ кодирования необязательных данных в случае, если в нашем коде имеется указатель на эти данные.
Важная деталь реализации, благодаря которой оба варианта дают одинаковый результат при кодировании, заключается в том, что значение TRUE равно 1, что совпадает с длиной массива переменной длины, когда в нем есть один элемент.
В листинге 16.18 приведен текст заголовочного файла, созданного программой rpcgen для данного файла спецификации.
Листинг 16.18. Заголовочный файл, получившийся в результате обработки листинга 16.17
//sunrpc/xdr1/opt1.h
7 struct optlong {
8 bool_t flag;
9 union {
10 long val;
11 } optlong_u;
12 };
13 typedef struct optlong optlong;
14 struct args {
15 optlong arg1;
16 struct {
17 u_int arg2_len;
18 long *arg2_val;
19 } arg2;
20 long *arg3;
21 };
22 typedef struct args args;
14-21 Хотя все три аргумента кодируются одинаково, способы присваивания и получения их значений в языке С различны.
В листинге 16.19 приведен текст простой пpoгрaммы, устанавливающей значения всех трех аргументов так, что ни одно из полей long не кодируется.
Листинг 16.19. Ни одно из значений не будет закодировано
//sunrpc/xdr1/opt1z.с
1 #include "unpipc.h"
2 #include "opt1.h"
3 int
4 main(int argc, char **argv)
5 {
6 int i;
7 XDR xhandle;
8 char *buff;
9 long *lptr;
10 args out;
11 size_t size;
12 out.arg1.flag = FALSE;
13 out.arg2.arg2_len = 0;
14 out.arg3 = NULL;
15 buff = Malloc(BUFFSIZE); /* Адрес должен быть кратен четырем */
16 xdrmem_create(&xhandle, buff, BUFFSIZE, XOR_ENCODE);
17 if (xdr_args(&xhandle, &out) != TRUE)
18 err_quit("xdr_args error");
19 size = xdr_getpos(&xhandle);
20 lptr = (long*)buff;
21 for (i = 0; i < size; i += 4)
22 printf("%ld ", (long) ntohl(*lptr++));
23 exit(0);
24 }
Присваивание значений
12-14 Дискриминанту объединения присваивается значение FALSE, длина массива переменной длины устанавливается в 0, а указатель делается нулевым (NULL).
Выделение буфера и кодирование
15-19 Мы выделяем буфер и кодируем структуру out в поток XDR.
Вывод содержимого буфера XDR
20-22 Мы выводим содержимое буфера XDR по 4 байта, используя функцию ntohl (host-to-network long integer) для преобразования из порядка XDR big-endian в байтовый порядок узла. В результате получается именно то, что должно было быть помещено в буфер библиотекой XDR времени выполнения:
solaris % opt1z
0
0
0
Как мы и предполагали, каждому аргументу отводится 4 байта со значением О, указывающим на то, что за ним не следует никаких данных.
В листинге 16.20 приведена измененная версия программы, которая присваивает значения всем трем аргументам, кодирует их в поток XDR и выводит его содержимое.
Листинг 16.20. Присваивание значений аргументам из листинга 16.17
//sunrpc/xdr1/opt1.c
1 #include "unpipc.h"
2 #include "opt1.h"
3 int
4 main(int argc, char **argv)
5 {
6 int i;
7 XOR xhandle;
8 char *buff;
9 long lval2, lval3, *lptr;
10 args out;
11 size_t size;
12 out.arg1.flag = TRUE;
13 out.arg1.optlong_u.val = 5;
14 lval2 = 9876;
15 out.arg2.arg2_len = 1;
16 out.arg2.arg2_val = &lval2;
17 lval3 = 123;
18 out.arg3 = &lval3;
19 buff = Malloc(BUFFSIZE); /* адрес должен быть кратен 4 */
20 xdrmem_create(&xhandle, buff, BUFFSIZE, XDR_ENCODE);
21 if (xdr_args(&xhandle, &out) != TRUE)
22 err_quit("xdr_args error");
23 size = xdr_getpos(&xhandle);
24 lptr = (long *) buff;
25 for (i = 0; i < size; i += 4)
26 printf("%ld ", (long) ntohl(*lptr++));
27 exit(0);
28 }
Присваивание значений
12-18 Для присваивания значения объединению мы устанавливаем дискриминант в TRUE, а затем присваиваем значение полю long. Длину массива мы также сначала устанавливаем в 1. Указатель мы устанавливаем на соответствующее значение в памяти.
При запуске этой программы мы получим ожидаемые шесть 4-байтовых значений:
solaris % opt1
1 значение дискриминанта TRUE
5
1 длина массива переменной длины
9876
1 флаг для ненулевого указателя
123
Данный текст является ознакомительным фрагментом.