Книга: UNIX: взаимодействие процессов

Пример: обработка связного списка

Пример: обработка связного списка

Если осуществима передача необязательных данных, мы можем расширить возможности указателей в XDR и использовать их для кодирования и декодирования связных списков, содержащих произвольное количество элементов. В нашем примере используется связный список пар имя-значение. Соответствующий файл спецификации XDR приведен в листинге 16.21.

Листинг 16.21. Спецификация XDR для связного списка пар имя-значение

//sunrpc/xdr1/opt2.x
1 struct mylist {
2  string name<>;
3  long value;
4  mylist *next;
5 };
6 struct args {
7  mylist *list;
8 };

1-5 Структура mylist содержит одну пару имя-значение и указатель на следующую структуру такого типа. Указатель в последней структуре списка будет нулевым.

В листинге 16.22 приведен текст заголовочного файла, созданного программой rpcgen из файла opt2.х.

Листинг 16.22. Заголовочный файл, созданный программой rpcgen

//sunrpc/xdr1/opt2.h
7  struct mylist {
8   char *name;
9   long value;
10  struct mylist *next;
11 };
12 typedef struct mylist mylist;
13 struct args {
14  mylist *list;
15 };
16 typedef struct args args;

В листинге 16.23 приведен текст программы, инициализирующей связный список с тремя парами имя-значение и кодирующей его с помощью библиотеки XDR.

Листинг 16.23. Инициализация, кодирование связного списка и вывод результата

1  //sunrpc/xdr1/opt2.c
2  #include "unpipc.h"
3  #include "opt2.h"
4  int
5  main(int argc, char **argv)
6  {
7   int i;
8   XDR xhandle;
9   long *lptr;
10  args out; /* структура, которую мы заполняем */
11  char *buff; /* результат кодирования */
12  mylist nameval[4]; /* до четырех элементов в списке */
13  size_t size;
14  out.list = &nameval[2]; /* [2] –> [1] –> [0] */
15  nameval[2].name = "name1";
16  nameval[2].value = 0x1111;
17  nameval[2].next = &nameval[1];
18  nameval[1].name = "namee2";
19  nameval[1].value = 0x2222;
20  nameval[1].next = &nameval[0];
21  nameval[0].name = "nameee3";
22  nameval[0].value = 0x3333;
23  nameval[0].next = NULL;
24  buff = Malloc(BUFFSIZE); /* адрес должен быть кратен 4 */
25  xdrmem_create(&xhandle, buff, BUFFSIZE, XDR_ENCODE);
26  if (xdr_args(&xhandle, tout) != TRUE)
27   err_quit("xdr_args error");
28  size = xdr_getpos(&xhandle);
29  lptr = (long*)buff;
30  for (i = 0; i < size; i += 4)
31   printf("%8lxn", (long)ntohl(*lptr++));
32  exit(0);
33 }

Инициализация связного списка

11-22 Мы выделяем память под четыре элемента, но инициализируем только три из них. Первая запись nameval[2], потом nameval[1] и nameval[0]. Указатель на начало списка (out.list) устанавливается на &nameval[2]. Мы инициализируем список в таком порядке, чтобы показать, что библиотека XDR обрабатывает указатели и порядок в списке оказывается именно таким, каким он был в нашей программе, и не зависит от того, какие массивы для этого используются. Мы также инициализируем значения элементов списка шестнадцатеричными величинами, поскольку будем выводить их в этом формате.

Вывод программы показывает, что перед каждым элементом списка идет значение 1 в 4 байтах (что мы можем считать длиной массива переменной длины с одним элементом или булевским значением TRUE). Четвертая запись состоит из 4 байт, в которых записан 0. Она обозначает конец списка:

solaris % opt2
1        дальше идет один элемент
5        длина строки
6e616d65 имя(name)
31000000 1 и три байта дополнения
1111     значение
1        один элемент
6        длина строки
6e616d65 имя
65320000 е 2 и 2 байта дополнения
2222     значение
1        один элемент
7        длина строки
6e616d65 имя
65653300 е е 3 и 1 байт дополнения
3333     значение
0        конец списка

При декодировании списка библиотека XDR будет динамически выделять память под его элементы и указатели и связывать все это вместе, что позволит легко переходить от одного элемента списка к другому в программе на С.

Оглавление книги


Генерация: 0.325. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз