Это команда rxgen, которую можно запустить в бесплатном хостинг-провайдере OnWorks, используя одну из наших многочисленных бесплатных онлайн-рабочих станций, таких как Ubuntu Online, Fedora Online, онлайн-эмулятор Windows или онлайн-эмулятор MAC OS.
ПРОГРАММА:
ИМЯ
rxgen - Генератор заглушек для пакета удаленного вызова процедур Rx
СИНТАКСИС
rxgen [-h | -c | -C | -S | -r] [-дкпР]
[-I директория] [-P префикс] [-o Outfile] [вводить]
rxgen -s перевозки [-o Outfile] [вводить]
rxgen -l [-o Outfile] [вводить]
rxgen -m [-o Outfile] [вводить]
ОПИСАНИЕ
rxgen это инструмент, который генерирует код C для реализации протокола Rx RPC; он принимает в качестве входных данных
описание интерфейса приложения, аналогичного C, и выводит номер сервера
и / или клиентские подпрограммы-заглушки, которые должны быть связаны с программами на основе RPC. Эти заглушки позволяют
программы для вызова удаленных процедур через локальные вызовы процедур. rxgen это расширение
Солнца rpcgen (версия 3.9) и сохраняет полную rpcgen функциональность (по крайней мере,
версия). Пожалуйста, обратитесь к rpcgen(1) для получения дополнительных сведений о флагах Sun RPC, и
к руководству по программированию RPC, касающемуся языка RPC, вместе с полезными примерами.
ДОПОЛНИТЕЛЬНЫЕ ОПЦИИ
rxgen работает в нескольких различных режимах. Сгенерированные выходные файлы могут быть созданы
индивидуально (используя один из -h, -c, -Cили -S) или вместе. Все выходные файлы
создается, когда используется значение по умолчанию (т. е. без параметров), или вывод ограничен
заглушки сервера (-C и -S) когда -r флаг используется. Ниже описаны типы
сгенерированные выходные файлы (для простоты имя файла относится к основному выходному имени файла):
-h Генерация определений данных C (файл заголовка) из стандартных определений RPCL (по умолчанию
расширение: имя файла.час).
-c Скомпилируйте процедуры XDR, необходимые для сериализации протокола, описанного RPCL.
Создание подпрограмм XDR для всех объявлений (расширение по умолчанию: имя файла.xdr.c).
-C Сгенерировать все клиентские подпрограммы-заглушки (расширение по умолчанию: имя файла.cs.c).
Вызов процедуры в этом файле приведет к тому, что аргументы будут упакованы и отправлены через
Rx (или R).
-S Сгенерировать все серверные подпрограммы-заглушки (расширение по умолчанию: имя файла.сс.в).
Аргументы распаковываются и вызывается соответствующая серверная процедура.
-r Создайте два файла расширений по умолчанию, созданных -C и -S настройки.
Следующие параметры можно использовать с любой комбинацией rxgen звонки:
-R Сгенерируйте код для более старого протокола \ R, в отличие от Rx, который используется по умолчанию.
-k Должен быть указан, если сгенерированный код предназначен для использования ядром;
специальные "включает" и другие особенности производятся, когда целевой вывод предназначен для
ядро.
-p Флаг комбинации пакетов: когда несколько пакетов включены в один
файл спецификации, одна процедура Execute Request будет использоваться для всех из них как
результат этого флага. По умолчанию создаются отдельные заглушки Execute Request для
каждый пакет.
-I директория
Как и в случае -I флаг в компиляторе C (cc). Этот флаг передается пре-
процессор (CPP) так что каталог директория ищется перед стандартным списком поиска для
# включать файлы. Как и ожидалось, несколько -I флаги можно использовать одновременно.
-P префикс
" префикс строка, следующая за этим переключателем, добавляется ко всем сгенерированным выходным файлам;
полезно, когда несколько запусков хотят создать разные версии одного и того же интерфейса
(скажем, версии с ядром и без ядра).
-d Режим отладки; только когда rxgen должен быть отлажен (скажем, через DBX).
-o Outfile
Укажите имя выходного файла. Если ничего не указано, стандартный вывод будет
использовал (-c, -h, -Cи -S только режимы). Обратите внимание, что если выходной файл указан в
опция файла с несколькими выводами (например, по умолчанию или с опцией -r), то Outfile
заменяет имя, сгенерированное по умолчанию (которое основано на основном
имя файла).
" -s, -lи -m варианты присутствуют только для rpcgen служба поддержки. Видеть rpcgen(1) для
информация об их использовании.
rxgen СИНТАКСИС РЕЗЮМЕ
Файл спецификации:
|
|
|
|
|
:
"упаковка"
:
"префикс"
:
"стартовый код"
:
"splitprefix" ";"
:
"IN =" "|"
"OUT =" "|"
:
["proc"] [ ] [ ]
["раскол" | "мульти"]
знак равно ] ";"
:
"(" ")"
:
["<" ">" | "[" "]"] | НУЛЕВОЙ
:
"," | НУЛЕВОЙ
:
«В» | «ВНЕ» | «INOUT» | НУЛЕВОЙ
:
| НУЛЕВОЙ
:
:
:
:
:
:
:
:
:
:
:
Синтаксис языка Sun RPCL (см. rpcgen(1))
rxgen КОМАНДЫ
Комментарии и предварительная обработка
Интерфейс ввода может содержать директивы препроцессора, которые передаются через C
препроцессор (то есть "cpp"). Поскольку препроцессор запускает все входные файлы до того, как они будут
фактически интерпретируется rxgen, все CPP директивы (#include, #ifdefs, #defines и т. д.)
законный и приветствуется в rxgen входной файл. Конечно, ни один из этих препроцессоров
директивы будут включены в любой из сгенерированных файлов. Чтобы облегчить различия
между различными типами выходных файлов, rxgen определяет некоторые особые CPP символы для
использовать rxgen программист. Это RPC_HDR (определяется при компиляции в заголовок,
имя файла.h, файлы), RPC_XDR (определяется при компиляции в xdr, имя файла.xdr.c, файлы),
RPC_CLIENT (определяется при компиляции в клиентские заглушки, имя файла.cs.c, файлы) и
RPC_SERVER (определяется при компиляции в заглушки сервера, имя файла.ss.c, файлы).
Кроме того, rxgen выполняет небольшую предварительную обработку самостоятельно. Любая строка, начинающаяся с "%", является
передается непосредственно в выходной файл, не интерпретируется rxgen. Для более тяжелых массовых
дамп неинтерпретированного кода, рекомендуется включать весь такой код в
"#include" и передайте его с пометкой "%". Интерфейс ввода также может содержать любые
Комментарии в стиле C, которые, конечно же, игнорируются. Интерпретация основана на токенах, поэтому
особая строчная ориентация отдельных операторов не требуется. rxgen также обеспечивает
довольно богатый и полезный набор отчетов об ошибках, идентифицирующих их по точному расположению строки и
тип ошибки. Также, rxgen автоматически сгенерирует строки #include для стандартного включения
файлы, такие как rx / xdr.h и rx / rx.hвместе со сгенерированным файлом заголовка из этого
интерфейс.
Префикс заглушки Процедуры
" пакет заявление говорит rxgen имя пакета интерфейса. Он используется для
префикс именования всех сгенерированных подпрограмм-заглушек и процедуры запроса на выполнение.
Например:
пакет AFS_
вызывает наименование процедуры запроса на выполнение AFS_ExecuteRequest (Предупреждение: в более раннем
version после имени пакета к имени ExecuteRequest был добавлен дополнительный символ «_»;
поэтому убедитесь, что у вас нет подпрограммы интерфейса ExecuteRequest) и заданной заглушки
подпрограмма, скажем Fetch, на самом деле будет называться AFS_Fetch. Множественные инструкции пакета (текущий
максимальный размер - 10) на конфигурацию разрешены и полезны, когда несколько наборов
реализованы интерфейсы (см. пример в конце). Обратите внимание, что в таких случаях использование
-p flag приводит к генерации только одной процедуры ExecuteRequest, которая
распознает несколько интерфейсов, чье имя предваряется префиксом первого пакета
утверждение. В случае по умолчанию будут созданы независимые процедуры ExecuteRequest для
каждая упакованная группа вызовов удаленных процедур.
" префикс оператор предоставляет имя, которое добавляется ко всем вызовам имен удаленных процедур в
подпрограмма-заглушка ExecuteRequest. Это полезно, когда сервер делает RPC-вызовы другим
серверы (скажем, для отладки). Например:
префикс S
заставляет имя "S" добавляться к имени всех подпрограмм, вызываемых с сервера
заглушки. Затем сервер может вызвать исходное имя и получить клиентские заглушки.
rxgen процедуры заявление
" процесс заявление является наиболее распространенным (и значимым) в rxgen интерфейс. Его синтаксис
описание:
[proc] [ ] [ ] ( , ..., )
[сплит | мульти] [= ];
где:
· "Proc" - необязательный префикс оператора процедуры. Это просто стилистический предмет
а не обязательный разделитель процедур.
· это название процедуры. Обратите внимание, что даже название процедуры
по желанию. Это имеет смысл только тогда, когда имя данной процедуры идентично
имя последнего пакет заявление (например, "пакет RCallBack" и объявление
процедура «RCallBack»).
· , если присутствует, заставляет процедуру ExecuteRequest вызывать эту заглушку вместо
автоматически сгенерированной заглушки при декодировании вызова с этим кодом операции.
· - константа или символ, являющийся кодом операции для этой процедуры. Можно использовать
функции препроцессора (например, #define), Const RPC-язык, или старый
хорошие константы как коды операций. Выполняется некоторая дальнейшая оценка / обработка кодов операций.
В частности, выполняются проверки на наличие повторяющихся и несуществующих кодов операций, а также
проверяет наличие «дыр» (т. е. пропусков в последовательных кодах операции) в последовательностях кодов операций. За
Например, мы используем тот факт, что при наличии "дыр" в кодах операций ExecuteRequest
процедура использует случаев оператор, а не более быстрый (и меньший по размеру код) проиндексированный
метод массива.
Таким образом, rxgen определяет (т. е. добавляет в файл заголовка) три ценных макроса для каждого
группа пакетов: LOWEST_OPCODE, HIGHEST_OPCODE и
NUMBER_OPCODES. Они могут быть полезны rxgen программист. Также,
обратите внимание, что опкод оператор является необязательной функцией и может быть опущен. В таком
случаях номера автоматических кодов операций генерируются последовательно, начиная с 0.
Можно изменить начальный номер кода операции, используя начальный код (из-за отсутствия
лучше имя) rxgen команда. Его синтаксис:
начальный код
где должно быть разумным! Учтите, что нельзя смешивать процедуры, некоторые с
коды операций и некоторые без них, а также разрешить коды операций после спецификации
начальный код заявление. rxgen будет жаловаться во всех таких случаях.
· The аргумент entry представляет заданный параметр процедуры. Его синтаксис:
[IN | INOUT | ВНЕ | ]
[ | <> | [макс] | []]
Если тип является косвенным (т. Е. За ним следует *), предполагается, что указатель
должен пройти один уровень, и указанные данные должны быть переданы. Это должно
обычно используется для всех структур / массивов и выходных параметров. Заметное исключение
когда указан явный максимальный размер массива / структуры; поскольку нет массива-указателя
объявления разрешены, следует использовать typedefs для достижения аналогичного эффекта. В
параметры могут быть входными параметрами (перед которыми стоит IN), выходными параметрами (перед ними
OUT) или параметры ввода / вывода (которым предшествует INOUT). Если не указано, то
используется направление предыдущего параметра в процедуре. (Примечание: первая
параметру должен предшествовать направленный примитив!)
· "Split" - это средство для работы с подпрограммами-заглушками, которые выполняют такие действия, как передача файлов или любые другие
другая операция, которая должна обмениваться информацией (например, длиной файла) перед
call возвращает свои выходные параметры. Из-за особого рукопожатия, которое
участвующих при удаленной передаче файлов, в настоящее время мы разбиваем все такие вызовы на два
клиентские подпрограммы-заглушки. Первый (с префиксом по умолчанию "Начать") используется для
передать все параметры IN и INOUT на сторону сервера. Второй (по умолчанию
префикс «Конец») используется для возврата параметров INOUT и OUT с сервера.
Между двумя вызовами пользователь должен выполнить соответствующие вызовы для файла.
перечислить. Например, следующее объявление процедуры в пакете AFS_
Fetch (IN a, b, INOUT c, OUT d) split = FETCHOPCODE;
примерно сгенерирует две независимые клиентские подпрограммы-заглушки:
BeginAFS_Fetch (В a, b, c)
и
EndAFS_Fetch (OUT c, d)
" разделенный префикс используется для изменения имен префиксов по умолчанию, используемых двумя
подпрограммы, созданные на стороне клиента, при работе с процедурами, связанными с передачей файлов
звонки. Например:
splitprefix IN = Before_ OUT = After_
вызовет именование двух клиентских заглушек для процедуры, связанной с передачей файлов, скажем
Принести(), быть Before_AFS_Fetch () и After_AFS_Fetch (), Соответственно.
· Опция "multi" почти идентична функции "split", описанной выше. Единственный
существенное видимое отличие состоит в том, что наряду с двумя клиентскими заглушками стандартный
также создается клиентская заглушка. Поскольку намерение состоит в том, чтобы обрабатывать вызовы с несколькими приемниками, мы
нужна вся стандартная заглушка процедуры в тех случаях, когда нет вызова multi-Rx
процедура выполняется. Побочным эффектом варианта «мульти» является создание
специальный макрос (например, "multi_ "который возвращает в качестве аргументов" Начать "
и заглушки "End" в выходном файле заголовка. Этот макрос используется непосредственно кодом Rx
когда выполняется вызов этой процедуры с несколькими приемниками.
ИСП rxgen ФУНКЦИИ И ОСОБЕННОСТИ
Хотя следующие команды rxgen все еще действуют, они скоро будут удалены, так как
есть альтернативы получше. НЕ ИСПОЛЬЗУЙТЕ ИХ!
" особый оператор - это временный прием, используемый для устранения некоторых неэффективных
стандартные процедуры xdr для обработки некоторых настроенных пользователем объявлений. В частности, это
применяется к указателю на строку, указанному как часть объявления. Например,
специальная структура BBS SeqBody;
говорит rxgen что запись "SeqBody" в пользовательской подпрограмме BBS xdr является строкой (примечание
что более одной строки могут быть "особенными" для каждой структуры - несколько строк разделяются
запятые); таким образом, он будет правильно распределять и освобождать пространство в сгенерированном сервером
заглушки, содержащие эту структуру как параметр IN или INOUT.
Лучшая альтернатива особый это подгонянный заявление, которое является просто
"индивидуальный" токен, за которым следует обычное объявление структуры на основе RPCL
правила. В этом случае объявление будет включено в сгенерированный заголовочный файл (-h
option), но для этой структуры не будет сгенерирована процедура xdr - пользователь предоставит
это. Все записи указателей в этой структуре будут запомнены, поэтому, когда структура
используется как IN или INOUT в заглушке сервера, утечки ядра не произойдет. Например,
считать
индивидуальная структура CBS {
длинный секлен;
char * SeqBody;
}
Подпрограмма "xdr_CBS" будет предоставлена пользователем, если во время выполнения кода операции DECODE xdr,
выделяется соответствующее пространство для строки «SeqBody». Точно так же освобождается это пространство.
во время выполнения кода операции FREE xdr.
Примечание. Старый стиль «Спецификации параметров массива» больше не поддерживается.
ПРИМЕРЫ
Если есть какие-то требования, недоступные текущему языку RPC, можно
настроить некоторые процедуры XDR, оставив эти типы данных неопределенными. Для каждого типа данных
который не определен, предполагается, что существует подпрограмма с добавленным именем "xdr_"
к нему. Выбранный набор rxgen функции представлены ниже, но для более полного
один (союзы, сложные примеры и т. д.) см. rpcgen Программирование Гид и
внешний Данные Представление: Вс Технические Заметки.
Определения типов
Оператор RPC typedef идентичен оператору typedef в C (т.е. "typedef ").
По умолчанию большинство объявлений пользователей (например, структуры, объединения и т. Д.) Автоматически
typedef'ed by rxgen. Поскольку это упрощает синтаксический анализ, его использование рекомендуется rxgen
скриптов.
Струны
Строковое соглашение C "char *" неоднозначно, так как обычно оно предназначено для
означает строку символов с завершающим нулем, но также может представлять указатель на
одиночный символ, указатель на массив символов и т. д. В языке RPC нуль-
завершенная строка однозначно называется "строкой". Примеры,
строка bigname <>;
имя строки ;
typedef строка имя тома ;
Обратите внимание, что максимальный размер строки может быть произвольным (например, "bigname" выше) или,
предпочтительно, или указывается в угловых скобках (т.е. "name" и "volname" выше). В
На практике в интерфейсах всегда следует использовать только ограниченные строки. Пример процедуры вызова
использование приведенных выше деклараций будет:
GetEntryByName (IN имя тома,
OUT struct vldbentry * entry) = VL_GETENTRYBYNAME;
или, конечно,
GetEntryByName (IN строка имя тома ,
OUT struct vldbentry * entry) = VL_GETENTRYBYNAME;
Для пользователя очень важно понимать, когда должны быть строковые параметры
выделяются и / или освобождаются его / ее клиентскими и / или серверными программами. Краткий анализ
Ниже следует обработка строковых параметров (обратите внимание, что аналогичный метод используется для обработки
массивы переменной длины, как будет показано ниже):
· На стороне клиента: строковые параметры IN и INOUT являются обязанностью программиста
и должен быть выделен (статическим или через malloc) перед вызовом rpc и освобожден (если
был использован malloc) после возврата rpc в клиентской программе пользователя; конечно, для
В параметрах INOUT возвращаемая строка не может быть больше ошибочной входной строки.
Параметры строки OUT автоматически искажаются (в зависимости от длины возвращаемого
строка, а не maxsize) rxgen клиентские заглушки (в имя файла.cs.c) и должны быть
освобождается клиентской программой; по общему признанию, это может сбивать с толку, поскольку пользователь
необходимо освободить то, что он / она не выделял.}
· На стороне сервера: строковые параметры IN и INOUT автоматически распределяются (на основе
размер входящих строк) заглушками сервера rxgen (в имя файла.ss.c) до того, как они
передаются в серверную процедуру пользователя; это пространство автоматически освобождается непосредственно перед
возвращается заглушка сервера rxgen; поэтому пользователю не нужно делать ничего особенного для IN
и строковые параметры INOUT.
Параметры строки OUT должны быть обработаны процедурой сервера пользователя (т. Е. Нулевой указатель
передается ему заглушкой сервера rxgen), и он автоматически освобождается в конце
rxgen заглушка сервера. Как и на стороне клиента, параметры OUT несколько
неортодоксальный (т. е. серверная процедура должна присвоить строку, не освобождая ее;
это делается rxgen заглушка сервера).
Обратите внимание, что для строковых параметров INOUT и OUT как на стороне клиента, так и на стороне сервера их
аргументы должны быть символами указателей (т.е. char **).
Указатели
Объявления указателя в RPC также точно такие же, как и в C (т. Е. "Struct
single_vldbentry * vldblist; "). Конечно, по сети нельзя отправлять указатели, но
можно использовать указатели XDR для отправки рекурсивных типов данных, таких как списки и деревья (
Пример связанного списка будет вскоре продемонстрирован).
Массивы
Фиксированные массивы аналогичны объявлениям стандартных массивов C (например, «struct UpdateEntry
записи [20] ") без каких-либо проблем с побочными эффектами в rxgen. Поскольку массивы переменной длины имеют
нет явного синтаксиса в C, для него используются угловые скобки, а объявления массивов
фактически скомпилирован в "структуры". Например, такие объявления как:
константа MAXBULKSIZE = 10000;
константа MAXENTRIES = 100;
непрозрачная масса ; / * Максимум 10000 элементов * /
int hosts <>; / * любое количество элементов * /
typedef vldbentry blkentries <100>; / * Предпочтительный массив decl * /
скомпилированы в следующие структуры:
структура {
u_int bulk_len; / * количество пунктов * /
char * bulk_val; / * указатель на массив * /
} масса;
для массива "bulk" и аналогично для массива blkentries <100>,
структура {
u_int blkentries_len; / * нет элементов в массиве * /
vldbentry * blkentries_val; / * указатель на массив * /
} элементы;
Поэтому пользователь должен знать о «магически» сгенерированных элементах структуры, таких как
количество элементов в массиве ( _len) и указатель на массив
( _val), так как некоторые записи нужно будет заполнить из
клиент-серверные программы. Примерный процесс будет:
typedef vldbentry blkentries ;
proc GetBlk (OUT blkentries * vlentries) = VL_GETBLK;
или, точнее,
GetBlk (OUT vldbentry vlentries ) = VL_GETBLK;
Обратите внимание, что хотя последний метод предпочтительнее, так как не нужно сначала использовать
оператор typedef (и, по общему признанию, программисты предпочитают избегать typedef), следует
представь это rxgen неявно выполняет расширение структуры и создание xdr; следовательно
пользователь должен знать поля "vldbentries_val" и "vldbentries_len", как и раньше.
(см. следующие примеры).
массив пример I (наименее желательно)
Объявление процедуры в конфигурации интерфейса:
proc ListAttributes (В атрибутах vldblistbyattributes *,
INOUT blkentries * vldbentries) = VL_LISTATTRIBUTES;
Пример кода КЛИЕНТА:
записи blkentries, * pnt;
Entries.blkentries_len = 10; / * максимальное количество возвращаемых записей * /
Entries.blkentries_val = (vldbentry *) malloc (LEN);
/ * Должен быть установлен * /
code = VL_ListAttributes (& атрибуты, & записи);
if (! code) {
pnt = записи.blkentries_val;
для (я = 0; я <entry.blkentries_len; я ++, pnt ++)
display_vldbentry (pnt);
/ * Убедитесь, что вы освободили выделенное место * /
бесплатно ((char *) entries.blkentries_val);
}
Пример кода СЕРВЕРА:
VL_ListAttributes (атрибуты, записи)
{
vldbentry * singleentry = entries-> blkentries_val;
записи-> blkentries_len = 0;
в то время как (copy_to_vldbentry (& vlentry, singleentry))
singleentry ++, vldbentries-> entries_len ++;
}
Хотя этот метод для массивов переменного размера работает нормально, он имеет ряд серьезных недостатков.
Параметр массива (например, vldbentries выше) должен быть объявлен как INOUT, поскольку нам нужно
передать максимальную длину ожидаемого возвращаемого массива; что еще важнее, большой (в зависимости от
значение "_len") кусок нежелательного кода будет передан на сервер в результате
побочного эффекта IN (out) массива. Это простой и удобный способ, если
размер возвращаемого массива можно предсказать с самого начала и когда размер достаточно велик. Этот
включен как пример ошибочного использования (и злоупотребления) rxgen и не должно быть
используемый.
массив пример II (Желательно метод)
Объявление процедуры в конфигурации интерфейса (с использованием примера I выше):
proc ListAttributes (В атрибутах vldblistbyattributes *,
OUT blkentries * vldbentries) = VL_LISTATTRIBUTES;
Пример кода КЛИЕНТА:
записи blkentries, * pnt;
code = VL_ListAttributes (& атрибуты, & записи);
if (! code) {
pnt = записи.blkentries_val;
для (я = 0; я <entry.blkentries_len; я ++, pnt ++)
display_vldbentry (pnt);
/ * Убедитесь, что вы освободили выделенное пространство (с помощью rxgen) * /
бесплатно ((char *) entries.blkentries_val);
}
Пример кода СЕРВЕРА:
VL_ListAttributes (атрибуты, записи)
{
vldbentry * singleentry;
записи-> blkentries_len = 0;
singleentry = записи-> blkentries_val
= (vldbentry *) malloc (MAXENTRIES * sizeof (vldbentry));
в то время как (copy_to_vldbentry (& vlentry, singleentry))
singleentry ++, vldbentries-> entries_len ++;
}
Это лучший (и самый простой) способ использования массивов переменного размера в качестве выходного параметра.
Серверная заглушка отвечает за таНос () адекватное пространство, которое
автоматически освобождается rxgen заглушка; клиентская сторона должна освободить место, выделенное
rxgen-вызывной стаб.
массив пример III (Связано Списки)
Учитывая следующие 3 объявления (возможно, применили некоторые оптимизации) в
конфигурационный файл:
typedef struct single_vldbentry * vldblist;
структура single_vldbentry {
влдбентри влентры;
влдблист следующий_влдб;
};
структура vldb_list {
узел vldblist;
};
и объявление процедуры rxgen:
LinkedList (В атрибутах vldblistbyattributes *,
OUT vldb_list * linkedentries) = VL_LINKEDLIST;
Пример кода КЛИЕНТА:
vldb_list connectedvldbs;
vldblist vllist, vllist1;
bzero (& connectedvldbs, sizeof (vldb_list));
code = VL_LinkedList (& атрибуты, & nentries, & connectedvldbs);
if (! code) {
printf ("Мы получили% d записей vldb \ n", nentries);
for (vllist = connectedvldbs.node; vllist; vllist = vllist1) {
vllist1 = vllist-> next_vldb;
display_entry (& vllist-> vlentry);
бесплатно ((char *) vllist);
}
}
Пример кода СЕРВЕРА:
VL_LinkedList (rxcall, атрибуты, записи, связанные vldbs);
{
vldblist vllist, * vllistptr = & connectedvldbs-> узел;
пока (...) {
vllist = * vllistptr
= (single_vldbentry *) malloc (sizeof (single_vldbentry));
copy_to_vldbentry (& tentry, & vllist-> vlentry);
nentries ++;
vllistptr = & vllist-> next_vldb;
};
* vllistptr = NULL;
}
Использование связанного списка дает много преимуществ: на сервер ничего не передается (параметр
ВЫХОДИТ), никаких дополнительных накладных расходов не требуется, и вызывающий абонент не должен явно
приготовьтесь к произвольному размеру возврата. Недостатком является то, что у вызывающего абонента есть
ответственность таНос () (на сервере) и бесплатно (на клиенте) каждой записи (для
Избегайте нежелательных протечек сердечника). Другой недостаток заключается в том, что поскольку это рекурсивный вызов, C
стек будет расти линейно по отношению к количеству узлов в списке (поэтому разумно
увеличьте стек Rx LWP, если ожидаются большие объемы данных - размер стека по умолчанию
составляет 4K). Здесь преимущества должны перевешивать недостатки.
Обратите внимание на комментарии к трем примерам массивов выше.
особенно когда они ссылаются на то, когда пользователь должен выделить / освободить место для
массивы переменной длины. Механизм очень похож на обработку строк, поэтому вы
может потребоваться просмотреть раздел строк выше; обратите внимание, что связанные списки обрабатываются
несколько иначе ...
Прочее Примеры реализованных проектов
Ниже приведена сокращенная версия случайного файла интерфейса, в котором показаны некоторые из распространенных
случаи.
/ * Объявление всех структур, используемых интерфейсом скрипта R.xg * /
структура AFSFid {
беззнаковый длинный том;
беззнаковый длинный Vnode;
беззнаковый длинный Уникальный;
};
typedef длинный ViceDataType;
/ * Обратите внимание, что ТЕСТ будет эквивалентен «ЗАГОЛОВКУ» только во время
обработка заголовка, * .h, файла * /
#ifdef RPC_HDR
#define ТЕСТ "ЗАГОЛОВОК"
#еще
#define ТЕСТ "ОТДЫХ"
#endif
/ * Это стандартный файл спецификации * .xg * /
пакет AFS_
splitprefix IN = BEFORE_ OUT = AFTER_;
Префиксный тест
proc Remove (IN struct AFSFid * Did, IN string volname <64>,
OUT struct AFSStatus * Статус) = AFS_REMOVE;
DisconnectFS AUX_disconnectFS () = AFS_DISCONNECTFS;
proc GetVolumeInfo (IN строка Vid,
OUT struct VolumeInfo * Информация) = AFS_GETVOLUMEINFO;
/ * У вас может быть больше интерфейса для каждой конфигурации * /
пакет VOTE_
/ * Использование "мульти" функции; таким образом, VOTE_Beacon можно назвать
вызов multi-Rx или как обычный вызов * /
Маяк (В долгом состоянии, долгое голосованиеStart,
net_version * версия, net_tid * tid)
мульти = VOTE_BEACON;
пакет DISK_
/ * Использование функции "разделения" * /
SendFile (В длинном файле, длинное смещение,
длинная длина, net_version * версия)
разделить = DISK_SENDFILE;
Результат of an фактического соединения интерфейс конфигурация
Мы продемонстрируем некоторые фактические результаты, полученные с помощью rxgen следуя сокращенному
актуальная конфигурация интерфейса.
Конфигурация файл
Содержимое файла конфигурации интерфейса (vldbint.xg):
пакет VL_
#include "vl_opcodes.h" / * Здесь указаны коды операций * /
% # include "vl_opcodes.h" / * прямо в другие места * /
/ * Текущие ограничения на параметры, влияющие на другие пакеты
(т.е. объем) * /
константа MAXNAMELEN = 65;
константа MAXNSERVERS = 8;
константа MAXTYPES = 3;
/ * Внешнее (видимое) представление отдельной записи vldb * /
структура vldbentry {
имя символа [MAXNAMELEN];
длинный тип тома;
длинные nServers;
длинный serverNumber [MAXNSERVERS];
длинный serverPartition [MAXNSERVERS];
длинные serverFlags [MAXNSERVERS];
u_long volumeId [MAXTYPES];
длинные флаги;
};
typedef struct single_vldbentry * vldblist;
структура single_vldbentry {
влдбентри влдбэнтри;
влдблист следующий_влдб;
};
структура vldb_list {
узел vldblist;
};
/ * вызовы интерфейса vldb * /
CreateEntry (в длинном Volid,
vldbentry * newentry) = VLCREATEENTRY;
GetEntryByName (IN строка volumename ,
OUT vldbentry * entry) = VLGETENTRYBYNAME;
GetNewVolumeId (В длинном счетчике,
OUT long * newvolumid) = VLGETNEWVOLUMEID;
ReplaceEntry (В длинном Volid,
длинный вольтип,
vldbentry * newentry,
длинный ReleaseType) multi = VLREPLACEENTRY;
ListAttributes (В атрибутах VldbListByAttributes *,
УДАЛИСЬ длинные записи,
OUT vldbentry bulkentries )
= ВЛИСТАТРИБУТЫ;
LinkedList (В атрибутах VldbListByAttributes *,
УДАЛИСЬ длинные записи,
OUT vldb_list * linkedentries) = VLLINKEDLIST;
Мы сконцентрируемся только на коде, сгенерированном Rx, поскольку код, сгенерированный R (-R опция)
скоро устареет. Подробное описание вызовов, связанных с Rx, внутри
сгенерированные заглушки (т. е. rx_NewCall (), rx_EndCall ()) вместе с подробностями о том, что происходит
внутри определенных вызовов (например, xdrrx_create ()) обратитесь к документации по Rx. Набор текста
"rxgen vldbint.xg" приведет к созданию четырех файлов: vldbint.h, vldbint.xdr.c,
vldbint.cs.c и vldbint.ss.c. Далее следует более внимательный взгляд на эти файлы.
заголовок файл (vldbint.h)
/ * Машинно сгенерированный файл - НЕ редактировать * /
#include "vl_opcodes.h" / * прямо в другие места * /
#define МАКСИМАЛЬНЫЙ 65
#определить MAXNSERVERS 8
# определить МАКСИМАЛЬНЫЕ ТИПЫ 3
структура vldbentry {
имя символа [MAXNAMELEN];
длинный тип тома;
длинные nServers;
длинный serverNumber [MAXNSERVERS];
длинный serverPartition [MAXNSERVERS];
длинные serverFlags [MAXNSERVERS];
u_long volumeId [MAXTYPES];
длинные флаги;
};
typedef struct vldbentry vldbentry;
bool_t xdr_vldbentry ();
typedef struct single_vldbentry * vldblist;
bool_t xdr_vldblist ();
структура single_vldbentry {
влдбентри влдбэнтри;
влдблист следующий_влдб;
};
typedef struct single_vldbentry single_vldbentry;
bool_t xdr_single_vldbentry ();
структура vldb_list {
узел vldblist;
};
typedef struct vldb_list vldb_list;
bool_t xdr_vldb_list ();
#включают
#define multi_VL_ReplaceEntry (Volid, voltype, newentry, ReleaseType) \
multi_Body (StartVL_ReplaceEntry (multi_call, Volid, voltype,
новая запись, ReleaseType), EndVL_ReplaceEntry(множественный_вызов))
typedef struct Bulkenties {
u_int объемные_len;
vldbentry * bulkentries_val;
} оптовые поставки;
bool_t xdr_bulkentries ();
/ * Полезная статистика, связанная с кодом операции для пакета: VL_ * /
# определить VL_LOWEST_OPCODE 501
# определить VL_HIGHEST_OPCODE 506
#define VL_NUMBER_OPCODES 6
Обратите внимание, что все структуры автоматически определяются по типу, и все "const" преобразуются в
"#define" s. Некоторые структуры данных, такие как групповые записи, берутся из параметров процедуры.
(из процедуры ListAttributes). Таким образом, это следует учитывать при создании заглушек.
по частям с rxgen (т. е. используя -c, -h, -Cили -S флаги). Также одна из сторон
эффекты опции "multi" (в процедуре "ReplaceEntry") - это генерация
"multi_VL_ReplaceEntry" выше.
XDR процедуры для структур (vldbint.xdr.c)
/ * Машинно сгенерированный файл - НЕ редактировать * /
#включают
#include "vldbint.h"
#include "vl_opcodes.h" / * прямо в другие места * /
bool_t
xdr_vldbentry (xdrs, objp)
XDR * xdrs;
vldbentry * objp;
{
если (! xdr_vector (xdrs, (char *) objp-> name, MAXNAMELEN,
sizeof (символ), xdr_char))
возврат (ЛОЖЬ);
если (! xdr_long (xdrs, & objp-> volumeType))
возврат (ЛОЖЬ);
если (! xdr_long (xdrs, & objp-> nServers))
возврат (ЛОЖЬ);
если (! xdr_vector (xdrs, (char *) objp-> serverNumber, MAXNSERVERS,
sizeof (длинный), xdr_long))
возврат (ЛОЖЬ);
если (! xdr_vector (xdrs, (char *) objp-> serverPartition,
MAXNSERVERS, sizeof (длинный), xdr_long))
возврат (ЛОЖЬ);
если (! xdr_vector (xdrs, (char *) objp-> serverFlags, MAXNSERVERS,
sizeof (длинный), xdr_long))
возврат (ЛОЖЬ);
если (! xdr_vector (xdrs, (char *) objp-> volumeId, MAXTYPES,
sizeof (u_long), xdr_u_long))
возврат (ЛОЖЬ);
если (! xdr_long (xdrs, & objp-> flags))
возврат (ЛОЖЬ);
возврат (ИСТИНА);
}
bool_t
xdr_vldblist (xdrs, objp)
XDR * xdrs;
vldblist * objp;
{
если (! xdr_pointer (xdrs, (char **) objp,
sizeof (struct single_vldbentry),
xdr_single_vldbentry))
возврат (ЛОЖЬ);
возврат (ИСТИНА);
}
bool_t
xdr_single_vldbentry (xdrs, objp)
XDR * xdrs;
single_vldbentry * objp;
{
если (! xdr_vldbentry (xdrs, & objp-> VldbEntry))
возврат (ЛОЖЬ);
если (! xdr_vldblist (xdrs, & objp-> next_vldb))
возврат (ЛОЖЬ);
возврат (ИСТИНА);
}
bool_t
xdr_vldb_list (xdrs, objp)
XDR * xdrs;
vldb_list * objp;
{
если (! xdr_vldblist (xdrs, & objp-> узел))
возврат (ЛОЖЬ);
возврат (ИСТИНА);
}
bool_t
xdr_bulkentries (xdrs, objp)
XDR * xdrs;
bulkentries * objp;
{
если (! xdr_array (xdrs, (char **) & objp-> bulkentries_val,
(u_int *) & objp-> bulkentries_len, MAXVLDBLEN,
sizeof (vldbentry), xdr_vldbentry))
возврат (ЛОЖЬ);
возврат (ИСТИНА);
}
Обратите внимание, что xdr_bulkentries () автоматически создается как побочный эффект процедуры
объявление параметра. Таким образом, если используются идентичные объявления параметров нескольких типов,
тогда будут созданы многократно определенные заглушки xdr_ *! Мы чувствовали, что это лучшая альтернатива
чтобы иметь rxgen программист имеет дело с такими типами, как bulkentries_1, bulkentries_2 ...
Сторона клиента заглушки процедуры (vldbint.cs.c)
/ * Машинно сгенерированный файл - НЕ редактировать * /
#включают
#включают
#включают
#include "vldbint.h"
#include "vl_opcodes.h" / * прямо в другие места * /
int VL_CreateEntry (z_conn, Volid, newentry)
регистр struct rx_connection * z_conn;
длинный волид;
влдбентри * новая запись;
{
struct rx_call * z_call = rx_NewCall (z_conn);
статический int z_op = 501;
интервал z_result;
XDR z_xdrs;
xdrrx_create (& z_xdrs, z_call, XDR_ENCODE);
/ * Маршалинг аргументов * /
если ((! xdr_int (& z_xdrs, & z_op))
|| (! xdr_long (& z_xdrs, & Volid))
|| (! xdr_vldbentry (& z_xdrs, newentry))) {
z_result = RXGEN_CC_MARSHAL;
перейти к неудаче;
}
z_result = RXGEN_SUCCESS;
неудача:
вернуть rx_EndCall (z_call, z_result);
}
int VL_GetEntryByName (z_conn, имя тома, запись)
регистр struct rx_connection * z_conn;
символ * имя тома;
влдбентри * запись;
{
struct rx_call * z_call = rx_NewCall (z_conn);
статический int z_op = 504;
интервал z_result;
XDR z_xdrs;
xdrrx_create (& z_xdrs, z_call, XDR_ENCODE);
/ * Маршалинг аргументов * /
если ((! xdr_int (& z_xdrs, & z_op))
|| (! xdr_string (& z_xdrs, & volumename, 65))) {
z_result = RXGEN_CC_MARSHAL;
перейти к неудаче;
}
/ * Отменить маршалинг аргументов ответа * /
z_xdrs.x_op = XDR_DECODE;
if ((! xdr_vldbentry (& z_xdrs, entry))) {
z_result = RXGEN_CC_UNMARSHAL;
перейти к неудаче;
}
z_result = RXGEN_SUCCESS;
неудача:
вернуть rx_EndCall (z_call, z_result);
}
int VL_GetNewVolumeId (z_conn, bumpcount, newvolumid)
регистр struct rx_connection * z_conn;
длинный отбойник;
длинный * новый объем;
{
struct rx_call * z_call = rx_NewCall (z_conn);
статический int z_op = 505;
интервал z_result;
XDR z_xdrs;
xdrrx_create (& z_xdrs, z_call, XDR_ENCODE);
/ * Маршалинг аргументов * /
если ((! xdr_int (& z_xdrs, & z_op))
|| (! xdr_long (& z_xdrs, & bumpcount))) {
z_result = RXGEN_CC_MARSHAL;
перейти к неудаче;
}
/ * Отменить маршалинг аргументов ответа * /
z_xdrs.x_op = XDR_DECODE;
if ((! xdr_long (& z_xdrs, newvolumid))) {
z_result = RXGEN_CC_UNMARSHAL;
перейти к неудаче;
}
z_result = RXGEN_SUCCESS;
неудача:
вернуть rx_EndCall (z_call, z_result);
}
int VL_ReplaceEntry (z_conn, Volid, voltype, newentry, ReleaseType)
регистр struct rx_connection * z_conn;
длинный Volid, voltype, ReleaseType;
влдбентри * новая запись;
{
struct rx_call * z_call = rx_NewCall (z_conn);
статический int z_op = 506;
интервал z_result;
XDR z_xdrs;
xdrrx_create (& z_xdrs, z_call, XDR_ENCODE);
/ * Маршалинг аргументов * /
если ((! xdr_int (& z_xdrs, & z_op))
|| (! xdr_long (& z_xdrs, & Volid))
|| (! xdr_long (& z_xdrs, & voltype))
|| (! xdr_vldbentry (& z_xdrs, новая запись))
|| (! xdr_long (& z_xdrs, & ReleaseType))) {
z_result = RXGEN_CC_MARSHAL;
перейти к неудаче;
}
z_result = RXGEN_SUCCESS;
неудача:
вернуть rx_EndCall (z_call, z_result);
}
int StartVL_ReplaceEntry (z_call, Volid, voltype, newentry, ReleaseType)
регистр struct rx_call * z_call;
длинный Volid, voltype, ReleaseType;
влдбентри * новая запись;
{
статический int z_op = 506;
интервал z_result;
XDR z_xdrs;
xdrrx_create (& z_xdrs, z_call, XDR_ENCODE);
/ * Маршалинг аргументов * /
если ((! xdr_int (& z_xdrs, & z_op))
|| (! xdr_long (& z_xdrs, & Volid))
|| (! xdr_long (& z_xdrs, & voltype))
|| (! xdr_vldbentry (& z_xdrs, новая запись))
|| (! xdr_long (& z_xdrs, & ReleaseType))) {
z_result = RXGEN_CC_MARSHAL;
перейти к неудаче;
}
z_result = RXGEN_SUCCESS;
неудача:
вернуть z_result;
}
интервал EndVL_ReplaceEntry (z_call)
регистр struct rx_call * z_call;
{
интервал z_result;
XDR z_xdrs;
z_result = RXGEN_SUCCESS;
неудача:
вернуть z_result;
}
int VL_ListAttributes (z_conn, атрибуты, nentries, bulkentries_1)
регистр struct rx_connection * z_conn;
VldbListByAttributes * атрибуты;
длинные * записи;
Bulkentries * bulkentries_1;
{
struct rx_call * z_call = rx_NewCall (z_conn);
статический int z_op = 511;
интервал z_result;
XDR z_xdrs;
xdrrx_create (& z_xdrs, z_call, XDR_ENCODE);
/ * Маршалинг аргументов * /
если ((! xdr_int (& z_xdrs, & z_op))
|| (! xdr_VldbListByAttributes (& z_xdrs, attributes))) {
z_result = RXGEN_CC_MARSHAL;
перейти к неудаче;
}
/ * Отменить маршалинг аргументов ответа * /
z_xdrs.x_op = XDR_DECODE;
если ((! xdr_long (& z_xdrs, nentries))
|| (! xdr_bulkentries (& z_xdrs, bulkentries_1))) {
z_result = RXGEN_CC_UNMARSHAL;
перейти к неудаче;
}
z_result = RXGEN_SUCCESS;
неудача:
вернуть rx_EndCall (z_call, z_result);
}
int VL_LinkedList (z_conn, атрибуты, элементы, элементы ссылок)
регистр struct rx_connection * z_conn;
VldbListByAttributes * атрибуты;
длинные * записи;
vldb_list * связанные записи;
{
struct rx_call * z_call = rx_NewCall (z_conn);
статический int z_op = 512;
интервал z_result;
XDR z_xdrs;
xdrrx_create (& z_xdrs, z_call, XDR_ENCODE);
/ * Маршалинг аргументов * /
если ((! xdr_int (& z_xdrs, & z_op))
|| (! xdr_VldbListByAttributes (& z_xdrs, attributes))) {
z_result = RXGEN_CC_MARSHAL;
перейти к неудаче;
}
/ * Отменить маршалинг аргументов ответа * /
z_xdrs.x_op = XDR_DECODE;
если ((! xdr_long (& z_xdrs, nentries))
|| (! xdr_vldb_list (& z_xdrs, linkedentries))) {
z_result = RXGEN_CC_UNMARSHAL;
перейти к неудаче;
}
z_result = RXGEN_SUCCESS;
неудача:
вернуть rx_EndCall (z_call, z_result);
}
Обратите внимание на побочный эффект функции «multi» (три разных модуля для «ReplaceEntry»
проц).
На стороне сервера заглушки процедуры (vldbint.ss.c)
/ * Машинно сгенерированный файл - НЕ редактировать * /
#включают
#включают
#включают
#include "vldbint.h"
#include "vl_opcodes.h" / * прямо в другие места * /
длинный _VL_CreateEntry (z_call, z_xdrs)
struct rx_call * z_call;
XDR * z_xdrs;
{
длинный z_результат;
длинный волид;
новая запись vldbentry;
если ((! xdr_long (z_xdrs, & Volid))
|| (! xdr_vldbentry (z_xdrs, & newentry))) {
z_result = RXGEN_SS_UNMARSHAL;
перейти к неудаче;
}
z_result = VL_CreateEntry (z_call, Volid и newentry);
неудача:
вернуть z_result;
}
длинный _VL_GetEntryByName (z_call, z_xdrs)
struct rx_call * z_call;
XDR * z_xdrs;
{
длинный z_результат;
char * volumename = (char *) 0;
запись vldbentry;
if ((! xdr_string (z_xdrs, & volumename, 65))) {
z_result = RXGEN_SS_UNMARSHAL;
перейти к неудаче;
}
z_result = VL_GetEntryByName (z_call, & volumename, & entry);
z_xdrs-> x_op = XDR_ENCODE;
если ((! xdr_vldbentry (z_xdrs, & entry)))
z_result = RXGEN_SS_MARSHAL;
неудача:
z_xdrs-> x_op = XDR_FREE;
если (! xdr_string (z_xdrs, & volumename, 65)) goto fail1;
вернуть z_result;
сбой1:
вернуть RXGEN_SS_XDRFREE;
}
длинный _VL_GetNewVolumeId (z_call, z_xdrs)
struct rx_call * z_call;
XDR * z_xdrs;
{
длинный z_результат;
длинный отбойник;
длинный newvolumid;
if ((! xdr_long (z_xdrs, & bumpcount))) {
z_result = RXGEN_SS_UNMARSHAL;
перейти к неудаче;
}
z_result = VL_GetNewVolumeId (z_call, bumpcount, & newvolumid);
z_xdrs-> x_op = XDR_ENCODE;
если ((! xdr_long (z_xdrs, & newvolumid)))
z_result = RXGEN_SS_MARSHAL;
неудача:
вернуть z_result;
}
длинный _VL_ReplaceEntry (z_call, z_xdrs)
struct rx_call * z_call;
XDR * z_xdrs;
{
длинный z_результат;
длинный Volid, voltype, ReleaseType;
новая запись vldbentry;
если ((! xdr_long (z_xdrs, & Volid))
|| (! xdr_long (z_xdrs, & voltype))
|| (! xdr_vldbentry (z_xdrs, & newentry))
|| (! xdr_long (z_xdrs, & ReleaseType))) {
z_result = RXGEN_SS_UNMARSHAL;
перейти к неудаче;
}
z_result = VL_ReplaceEntry (z_call, Volid, voltype и newentry,
тип выпуска);
неудача:
вернуть z_result;
}
длинные _VL_ListAttributes (z_call, z_xdrs)
struct rx_call * z_call;
XDR * z_xdrs;
{
длинный z_результат;
Атрибуты VldbListByAttributes;
долгие дни;
насыпные насыпи насыпные_1;
if ((! xdr_VldbListByAttributes (z_xdrs, & attributes))) {
z_result = RXGEN_SS_UNMARSHAL;
перейти к неудаче;
}
z_result = VL_ListAttributes (z_call, & атрибуты, & nentries,
& bulkentries_1);
z_xdrs-> x_op = XDR_ENCODE;
если ((! xdr_long (z_xdrs, & nentries))
|| (! xdr_bulkentries (z_xdrs, & bulkentries_1)))
z_result = RXGEN_SS_MARSHAL;
неудача:
z_xdrs-> x_op = XDR_FREE;
если (! xdr_bulkentries (z_xdrs, & bulkentries_1)) goto fail1;
вернуть z_result;
сбой1:
вернуть RXGEN_SS_XDRFREE;
}
длинный _VL_LinkedList (z_call, z_xdrs)
struct rx_call * z_call;
XDR * z_xdrs;
{
длинный z_результат;
Атрибуты VldbListByAttributes;
долгие дни;
vldb_list связанные записи;
if ((! xdr_VldbListByAttributes (z_xdrs, & attributes))) {
z_result = RXGEN_SS_UNMARSHAL;
перейти к неудаче;
}
z_result = VL_LinkedList (z_call, & атрибуты, & nentries,
& linkedentries);
z_xdrs-> x_op = XDR_ENCODE;
если ((! xdr_long (z_xdrs, & nentries))
|| (! xdr_vldb_list (z_xdrs, & linkedentries)))
z_result = RXGEN_SS_MARSHAL;
неудача:
вернуть z_result;
}
длинный _VL_CreateEntry ();
long _VL_GetEntryByName ();
long _VL_GetNewVolumeId ();
long _VL_ReplaceEntry ();
длинный _VL_ListAttributes ();
длинный _VL_LinkedList ();
static long (* StubProcsArray0 []) () = {_VL_CreateEntry,
_VL_GetEntryByName, _VL_GetNewVolumeId, _VL_ReplaceEntry,
_VL_ListAttributes, _VL_LinkedList};
VL_ExecuteRequest (z_call)
регистр struct rx_call * z_call;
{
инт оп;
XDR z_xdrs;
длинный z_результат;
xdrrx_create (& z_xdrs, z_call, XDR_DECODE);
если (! xdr_int (& z_xdrs, & op))
z_result = RXGEN_DECODE;
иначе, если (op <VL_LOWEST_OPCODE || op> VL_HIGHEST_OPCODE)
z_result = RXGEN_OPCODE;
еще
z_result = (* StubProcsArray0 [op - VL_LOWEST_OPCODE])
(z_call, & z_xdrs);
вернуть z_result;
}
Если в последовательности опкодов процедур были пробелы, то код для VL_ExecuteRequest ()
процедура была бы кардинально другой (это было бы утверждение случая для
каждую процедуру).
ПРИМЕЧАНИЯ
rxgen реализуется от Sun rpcgen полезность. Все стандартные rpcgen's
функциональность полностью поддерживается. Обратите внимание, что некоторые активные rpcgen варианты, которые не применяются
в rxgenцель здесь не упоминается (т. е. -s, -l, -m варианты) и заинтересованные
читатель должен обратиться к rpcgen(1) для подробностей.
Когда "% # include" используется функция убедитесь, что у вас нет
rxgen языковых функций (например,% # определяет), так как вы получите синтаксические ошибки во время
сборники ..
Поскольку это текущий проект, многие из вышеперечисленного могут измениться / исчезнуть без серьезного вмешательства.
предупреждение.
Используйте rxgen онлайн с помощью сервисов onworks.net