rpcgen можно использовать для создания процедур XDR, которые будут преобразовывать локальные структуры данных в формат XDR и наоборот.
Пусть dir.x содержит сервис удаленного чтения каталога, созданный с помощью rpcgen, процедуры сервера и процедуры XDR.
Файл описания протокола RPC dir.x имеет следующий вид:
* dir.x: Протокол вывода удаленного каталога
*/
/*максимальная длина элемента каталога */
const MAXNAMELEN = 255;
/* элемент каталога */
typedef string nametype<MAXNAMELEN>;
/* ссылка в списке */
typedef struct namenode *namelist;
/* Узел в списке каталога */
struct namenode {
nametype name; /* имя элемента каталога */
namelist next; /* следующий элемент */
};
union readdir_res switch (int errno) {
case 0:
namelist list; /* нет ошибок:
возвращает оглавление каталога */
default:
void; /*возникла ошибка: возвращать нечего*/
};
/* Определение программы каталога */
program DIRPROG {
version DIRVERS {
readdir_res
READDIR(nametype) = 1;
} = 1;
} = 0x20000076;
При запуске rpcgen для dir.x создаются четыре файла:
Серверная часть процедуры READDIR, в файле dir_proc.c:
* dir_proc.c: удаленная реализация readdir
*/
#include <dirent.h>
#include "dir.h" /* Создается rpcgen */
extern int errno;
extern char *malloc();
extern char *strdup();
readdir_res *
readdir_1(nametype *dirname, struct svc_req *req)
{
DIR *dirp;
struct dirent *d;
namelist nl;
namelist *nlp;
static readdir_res res; /* должен быть static! */
/* Открыть каталог */
dirp = opendir(*dirname);
if (dirp == (DIR *)NULL) {
res.errno = errno;
return (&res);
}
/* Очистить предыдущий результат */
xdr_free(xdr_readdir_res, &res);
/*
* Собрать элементы каталога.
*/
nlp = &res.readdir_res_u.list;
while (d = readdir(dirp)) {
nl = *nlp = (namenode *)
malloc(sizeof(namenode));
if (nl == (namenode *) NULL) {
res.errno = EAGAIN;
closedir(dirp);
return(&res);
}
nl->name = strdup(d->d_name);
nlp = &nl->next;
}
*nlp = (namelist)NULL;
/* Вывести результат */
res.errno = 0;
closedir(dirp);
return (&res);
}
Клиентская часть процедуры READDIR, файл rls.c:
* rls.c: Клиент для удаленного чтения каталогов
*/
#include <stdio.h>
#include "dir.h" /* создается rpcgen */
extern int errno;
main(int argc, char *argv[])
{
CLIENT *clnt;
char *server;
char *dir;
readdir_res *result;
namelist nl;
if (argc != 3) {
fprintf(stderr, "usage: %s host
directory\n",argv[0]);
exit(1);
}
server = argv[1];
dir = argv[2];
/*
* Создает обработчик клиента,
* вызывающий MESSAGEPROG на сервере
*/
cl = clnt_create(server, DIRPROG, DIRVERS, "tcp");
if (clnt == (CLIENT *)NULL) {
clnt_pcreateerror(server);
exit(1);
}
result = readdir_1(&dir, clnt);
if (result == (readdir_res *)NULL) {
clnt_perror(clnt, server);
exit(1);
}
/* Успешный вызов удаленной процедуры. */
if (result->errno != 0) {
/* Ошибка на удаленной системе.
*/
errno = result->errno;
perror(dir);
exit(1);
}
/* Оглавление каталога получено.
* Вывод на экран.
*/
for (nl = result->readdir_res_u.list;
nl != NULL;
nl = nl->next) {
printf("%s\n", nl->name);
}
xdr_free(xdr_readdir_res, result);
clnt_destroy(cl);
exit(0);
}
Код клиента, создаваемый rpcgen, не освобождает память, выделенную для результатов запроса RPC. Поэтому следует вызывать xdr_free(), чтобы освободить память после завершения работы. Это похоже на вызов free(), за исключением того, что здесь для получения результата передается процедура XDR.