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("%8lx\n", (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
31000000
1111
1
6
6e616d65
65320000
2222
1
7
6e616d65
65653300
3333
0
При декодировании списка библиотека XDR будет динамически выделять память под его элементы и указатели и связывать все это вместе, что позволит легко переходить от одного элемента списка к другому в программе на С.
16.9. Форматы пакетов RPC
На рис. 16.5 приведен формат запроса RPC в пакете TCP.
Поскольку TCP передает поток байтов и не предусматривает границ сообщений, приложение должно предусматривать способ разграничения сообщений. Sun RPC определяет запись как запрос или ответ, и каждая запись состоит из одного или более фрагментов. Каждый фрагмент начинается с 4-байтового значения: старший бит является флагом последнего фрагмента, а следующие 31 бит представляют собой счетчик (длина фрагмента). Если бит последнего фрагмента имеет значение 0, данный фрагмент не является последним в записи.
ПРИМЕЧАНИЕ
Это 4-байтовое значение передается в порядке big-endian, так же как и 4-байтовые целые в XDR, но оно не относится к стандарту XDR, поскольку он не предусматривает передачи битовых полей.
Если вместо TCP используется UDP, первое поле в заголовке UDP будет идентификатором транзакции (XID), как показано на рис. 16.7.
ПРИМЕЧАНИЕ
При использовании TCP на размер запроса и ответа RPC ограничения не накладываются, поскольку может использоваться любое количество фрагментов, а длина каждого из них задается 31-разрядным целым. Но при использовании протокола UDP запрос (и ответ) должен помещаться в дейтаграмму целиком, а максимальное количество данных в ней — 65507 байт (для IPv4). Во многих реализациях, предшествовавших TI-RPC, размер ограничивался значением около 8192 байт, поэтому если требуется передавать более 8000 байт, следует пользоваться протоколом TCP.
Рис. 16.5. Запрос RPC в пакете TCP