这是 rxgen 命令,可以使用我们的多个免费在线工作站之一在 OnWorks 免费托管服务提供商中运行,例如 Ubuntu Online、Fedora Online、Windows 在线模拟器或 MAC OS 在线模拟器
程序:
您的姓名
rxgen - Rx 远程过程调用包的存根生成器
概要
瑞克斯根 [-h | -c | -C | -S | -r[-dkpR]
[-I DIR[-P 字首[-o 输出文件[入档]
瑞克斯根 -s 运输 [-o 输出文件[入档]
瑞克斯根 -l [-o 输出文件[入档]
瑞克斯根 -m [-o 输出文件[入档]
商品描述
瑞克斯根 是一个生成C代码来实现Rx RPC协议的工具; 它作为输入
一个类似于 C 的应用程序接口的描述,并产生许多服务器
和/或客户端存根例程与基于 RPC 的程序链接。 这些存根允许
程序通过本地过程调用来调用远程过程。 瑞克斯根 是一个扩展
孙氏的 rpcgen (版本 3.9)并保留完整 rpcgen 功能(至少从那时起
版本)。 请参阅 rpcgen(1) 有关 Sun 的 RPC 特定标志的更多详细信息,以及
到有关 RPC 语言的 RPC 编程指南以及有用的示例。
配置
瑞克斯根 在几种不同的模式下运行。 可以生成生成的输出文件
单独(使用其中之一 -h, -c, -C或 -S) 或统称。 所有输出文件都是
在使用默认值(即没有选项)时创建,或者输出仅限于
服务器存根(-C 和 -S) 当。。。的时候 -r 标志被使用。 下面分别介绍一下
生成的输出文件(为简单起见, 文件名 指主输出文件名):
-h 从标准 RPCL 定义(默认值)生成 C 数据定义(头文件)
延期: 文件名。H)。
-c 编译序列化 RPCL 描述的协议所需的 XDR 例程。
为所有声明生成 XDR 例程(默认扩展名: 文件名.xdr.c)。
-C 生成所有客户端存根例程(默认扩展名: 文件名.cs.c)。
调用此文件中的例程将导致参数被打包并通过
Rx(或 R)。
-S 生成所有服务器端存根例程(默认扩展名: 文件名.ss.c)。
参数被解包,并调用相应的服务器例程。
-r 生成两个默认的扩展文件 -C 和 -S 选项。
以下选项可用于任意组合 瑞克斯根 致电:
-R 为旧的 \R 协议生成代码,而不是 Rx,这是默认的。
-k 当生成的代码打算供内核使用时必须指定;
当目标输出用于
核心。
-p 包组合标志:当一个包中包含多个包时
规范文件,一个单一的执行请求例程将用于所有它们作为
这个标志的结果。 默认是生成单独的执行请求存根
每个包。
-I DIR
类似于 -I C 编译器中的标志 (cc)。 这个标志被传递给预
处理器(CPP) 所以那个目录 DIR 在标准查找列表之前搜索
#include 文件。 正如预期的那样,多个 -I 标志可以同时使用。
-P 字首
这款 字首 此开关后面的字符串被添加到所有生成的输出文件中;
当多次运行想要生成同一界面的不同版本时很有用
(例如,内核和非内核版本)。
-d 调试模式; 仅在需要时 瑞克斯根 将被调试(例如,通过 DBX).
-o 输出文件
指定输出文件的名称。 如果未指定,则标准输出为
用过的 (-c, -h, -C及 -S 仅模式)。 请注意,如果在一个输出文件中指定了
多输出文件选项(如默认,或带选项 -r),然后 输出文件
替换默认生成的名称(基于配置的主
文档名称)。
这款 -s, -l及 -m 选项仅用于 rpcgen 支持。 看 rpcgen(1)
有关其使用的信息。
瑞克斯根 句法 概要
规格文件:
|
|
|
|
|
:
“包裹”
:
“字首”
:
“起始操作码”
:
“拆分前缀” ";"
:
“在 =” “|”
“输出=” “|”
:
[“过程”] [ ] [ ]
[“分裂” | “多”]
["=" ] ";"
:
“(” ")"
:
[“<” ">" | “[” "]"] | 空值
:
“,” | 空值
:
“在” | “出” | “输入” | 空值
:
| 空值
:
:
:
:
:
:
:
:
:
:
:
Sun 的 RPCL 语言语法(请参阅 rpcgen(1))
瑞克斯根 指令
评论 和 前处理
输入接口可能包含通过 C 传递的预处理器指令
预处理器(即“cpp”)。 由于预处理器在所有输入文件上运行之前
实际上解释为 瑞克斯根所有 CPP 指令(#include、#ifdefs、#defines 等)是
合法并受到欢迎 瑞克斯根 输入文件。 当然,这些预处理器都没有
指令将包含在任何生成的文件中。 为了便于区分
在不同类型的输出文件之间, 瑞克斯根 定义了某些特殊的 CPP 符号为
使用 瑞克斯根 程序员。 这些是 RPC_HDR(在编译成头文件时定义,
文件名.h,文件),RPC_XDR(编译成xdr时定义, 文件名.xdr.c,文件),
RPC_CLIENT(在编译到客户端存根时定义, 文件名.cs.c,文件),以及
RPC_SERVER(在编译成服务器存根时定义, 文件名.ss.c,文件)。
此外, 瑞克斯根 自己做一些预处理。 任何以“%”开头的行都是
直接传递到输出文件中,不被解释 瑞克斯根. 对于更重的集体
转储未解释的代码,建议将所有此类代码包含在
“#include”文件并将其以“%”开头。 输入接口也可能包含任何
当然,C 风格的注释会被忽略。 解释是基于令牌的,因此
不需要单独语句的特殊行方向。 瑞克斯根 还提供了一个
非常丰富和有用的错误报告集,通过准确的线路位置和
错误类型。 还, 瑞克斯根 将自动为标准包含生成#include 行
文件,例如 RX/XDR.h 和 接收/接收.h, 以及由此生成的头文件
界面。
前缀 存根 程序
这款 包 声明告诉 瑞克斯根 接口包的名称。 它用于
为所有生成的存根例程和执行请求过程的命名添加前缀。
例如:
包 AFS_
导致执行请求过程被命名为 AFS_ExecuteRequest(警告:在较旧的
版本在包名称之后附加了一个额外的“_”到 ExecuteRequest 名称;
因此请确保您没有 ExecuteRequest 接口例程)和给定的存根
例程,比如说 Fetch,实际上被命名为 AFS_Fetch。 多个包语句(当前
允许每个配置的最大大小为 10),并且在多组配置时很有用
接口被实现(见最后的例子)。 请注意,在这种情况下,使用
此 -p 标志导致仅生成一个 ExecuteRequest 过程,该过程
识别多个接口,其名称以第一个包为前缀
陈述。 在默认情况下,将创建独立的 ExecuteRequest 过程
每个打包的远程过程调用组。
这款 字首 语句提供一个名称,以添加到对远程过程名称的所有调用之前
ExecuteRequest 存根例程。 当服务器向其他服务器发出 RPC 调用时很有用
服务器(例如,出于调试目的)。 例如:
前缀 S
导致名称“S”被添加到从服务器调用的所有例程的名称之前
存根。 然后服务器可以调用原始名称并获取客户端存根。
瑞克斯根 程序 声明
这款 进程 陈述是最常见(也最有意义)的 瑞克斯根 界面。 它的语法
描述是:
[过程] [ ] [ ] ( , ..., )
[分裂| 多] [= ];
其中:
· “proc”是过程语句的可选前缀。 这只是一个风格项目
而不是必需的过程分隔符。
· 是过程的名称。 请注意,即使程序的名称是
可选的。 这仅在给定过程的名称与
最后的名字 包 声明(即“package RCallBack”和声明
“RCallBack”过程)。
· ,如果存在,则导致 ExecuteRequest 过程改为调用该存根
解码具有该操作码的调用时自动生成的存根。
· 是作为该过程的操作码的常量或符号。 一个可能会用
预处理器功能(即#define), 常量 RPC 语言功能,或旧的
好的常量作为操作码。 对操作码进行了一些进一步的评估/处理。
特别是,检查重复和不存在的操作码,以及
检查操作码序列中的“漏洞”(即连续操作码中的间隙)。 为了
例如,我们使用这样一个事实,即当操作码中存在“漏洞”时,ExecuteRequest
程序使用 案件 语句而不是更快(更小,代码方式)索引
数组方法。
也, 瑞克斯根 为每个定义(即附加到头文件)三个有价值的宏
包组: LOWEST_OPCODE, HIGHEST_OPCODE,和
NUMBER_OPCODES。 这些可能对 瑞克斯根 程序员。 还,
请注意, 操作码 语句是一个可选功能,可以省略。 在这样的
在这种情况下,自动操作码编号从 0 开始按顺序生成。
可以使用以下命令更改初始操作码编号 起始操作码 (由于缺乏
更好的名字) 瑞克斯根 命令。 它的语法是:
起始操作码
在哪里必须合理! 注意一个程序不能混用,有的用
操作码和一些没有,也不允许在指定之后的操作码
起始操作码 语句。 瑞克斯根 将在所有此类情况下投诉。
· 论点 条目表示过程的给定参数。 它的语法是:
[在| 输入输出 | 出 | ]
[ |<>|[最大]|[]]
如果类型是间接类型(即后跟 *),则假定指针
应遵循一级,指向的数据将被传输。 这应该
通常用于所有结构/数组和输出参数。 一个明显的例外
是在给出显式数组/结构最大大小时; 因为没有指针数组
声明是允许的,应该使用 typedef 来实现类似的效果。 这
参数可以是输入参数(以 IN 开头)、输出参数(以
OUT) 或输入/输出参数(以 INOUT 开头)。 如果未指定,则
使用程序中前一个参数的方向。 (注:第一
参数前面必须有方向原语!)
·“拆分”是一种处理存根例程的技巧,这些例程执行诸如文件传输或任何
其他必须在执行之前交换信息(例如,文件的长度)的操作
调用返回其输出参数。 因为特殊的握手是
在进行远程文件传输时涉及,我们目前将所有此类调用分为两个
客户端存根例程。 第一个(带有默认前缀“Begin”)用于
将所有 IN 和 INOUT 参数传递给服务器端。 第二个(默认
“End”前缀)用于从服务器取回 INOUT 和 OUT 参数。
在两次调用之间,用户应该对文件进行适当的调用
转移。 例如,包 AFS_ 中的以下过程声明
获取 (IN a, b,INOUT c, OUT d) split = FETCHOPCODE;
将大致生成两个独立的客户端存根例程:
BeginAFS_Fetch(IN a、b、c)
和
EndAFS_Fetch(OUT c, d)
这款 拆分前缀 语句用于更改两者使用的默认前缀名称
客户端存根在处理文件传输相关过程时生成的例程
调用。 例如:
分割前缀 IN=Before_ OUT=After_
将导致为文件传输相关例程命名两个客户端存根,例如
拿来(), 成为 Before_AFS_Fetch() 和 After_AFS_Fetch()。
· “multi”选项与上述“split”功能几乎相同。 唯一的
显着的明显区别是,除了两个客户端存根之外,标准
还会生成客户端存根。 由于目的是处理多接收调用,我们
在没有多 Rx 调用的情况下需要整个标准程序存根
程序进行。 “multi”选项的一个副作用是生成一个
特殊宏(即“multi_ " 作为参数传回 "Begin"
和头输出文件中的“结束”存根。 这个宏直接被 Rx 代码使用
当执行此过程的多接收调用时。
过时 瑞克斯根 功能
尽管以下 rxgen 命令仍然有效,但它们很快将被删除,因为
有更好的选择。 不要使用它们!
这款 特别 语句是用于处理某些低效率的临时黑客
用于处理一些用户自定义声明的标准 xdr 例程。 特别是,这
适用于作为声明一部分指定的字符串指针。 例如,
特殊结构 BBS SeqBody;
告诉 瑞克斯根 用户定义的 BBS xdr 例程中的条目“SeqBody”是一个字符串(注意
每个结构可以有多个字符串是“特殊的”——多个字符串由
逗号); 因此,它将在服务器生成的空间中正确分配和取消分配空间
包含此结构作为 IN 或 INOUT 参数的存根。
更好的替代品 特别 是 定制 声明,这只是
“自定义”标记后跟基于 RPCL 的结构的常规声明
规则。 在这种情况下,声明将包含在生成的头文件中(-h
选项)但不会为此结构生成 xdr 例程——用户将提供
这个。 该结构中的所有指针条目都将被记住,因此当该结构被
在服务器存根中用作 IN 或 INOUT,不会发生核心泄漏。 例如,
考虑
自定义结构 CBS {
长序列;
字符 *SeqBody;
}
“xdr_CBS”例程将由用户提供,在解码 xdr 操作码期间,
为“SeqBody”字符串分配了适当的空间。 同样,该空间被释放
在免费 xdr 操作码期间。
注意:不再支持旧样式的“数组参数规范”。
示例
如果有一些当前 RPC 语言不具备的要求,可以
通过不定义这些数据类型来自定义一些 XDR 例程。 对于每种数据类型
这是未定义的,将假定存在名称为“xdr_”的例程
到它。 一组精选 瑞克斯根 下面介绍了功能,但为了更全面
一(联合,复杂的例子等)请参考 rpcgen 代码编程 产品指南 和
外部的 时间 表示: 星期天 技术 笔记.
类型定义
RPC typedef 语句与 C typedef 相同(即“typedef ”)。
默认情况下,大多数用户声明(即结构、联合等)是自动
类型定义由 瑞克斯根. 由于它使解析更简单,因此推荐使用它 瑞克斯根
脚本。
琴弦
C "char *" 字符串约定有点模棱两可,因为它通常用于
表示以空字符结尾的字符串,但也可以表示指向
单个字符、指向字符数组的指针等。在 RPC 语言中,空-
终止的字符串明确称为“字符串”。 例子,
字符串大名<>;
字符串名称;
typedef 字符串 卷名;
请注意,字符串的最大大小可以是任意的(如上面的“bigname”),或者,
最好,或在尖括号中指定(即上面的“name”和“volname”)。 在
实践中,应该始终在接口中只使用有界字符串。 示例调用过程
使用上述声明将是:
GetEntryByName (IN 卷名,
OUT 结构 vldbentry *entry) = VL_GETENTRYBYNAME;
或者,当然,
GetEntryByName (IN 字符串 volname ,
OUT 结构 vldbentry *entry) = VL_GETENTRYBYNAME;
用户了解何时应该使用字符串参数是非常重要的
由他/她的客户端和/或服务器程序分配和/或释放。 简要分析
字符串参数处理如下(注意类似的方法用于处理
可变长度数组,稍后将显示):
· 在客户端:IN 和 INOUT 字符串参数是程序员的责任
并且应该在调用 rpc 之前分配(静态或通过 malloc)并释放(如果
在用户的客户端程序中rpc返回后使用了malloc); 当然,对于
INOUT 参数,返回的字符串不能大于malloced 的输入字符串。
OUT 字符串参数自动分配(根据返回的长度
字符串而不是最大大小)由 瑞克斯根 客户端存根(在 文件名.cs.c) 并且必须是
被客户端程序释放; 诚然,这可能有点令人困惑,因为用户
需要释放他/她没有分配的东西。}
· 在服务器端:IN 和 INOUT 字符串参数自动分配(基于
传入字符串的大小)由 rxgen 服务器存根(在 文件名.ss.c) 在他们之前
传递给用户的服务器程序; 该空间在之前自动释放
rxgen 服务器存根返回; 因此用户不需要为 IN 做任何特别的事情
和 INOUT 字符串参数。
OUT 字符串参数必须由用户的服务器过程分配(即空指针
由 rxgen 服务器存根传递给它)并在结束时自动释放
此 瑞克斯根 服务器存根。 像在客户端一样,OUT 参数有点
非正统的(即服务器例程必须 malloc 一个字符串,而不会自己释放它;
这是由 瑞克斯根 服务器存根)。
请注意,对于 INOUT 和 OUT 字符串参数,在客户端和服务器端它们的
参数必须是指针的字符(即字符**)。
Pointers
RPC 中的指针声明也与 C 中的完全一样(即“struct
single_vldbentry *vldblist;"). 当然,不能通过网络发送指针,但是
可以使用 XDR 指针发送递归数据类型,例如列表和树(一种
链接列表的示例将在稍后演示)。
阵列
固定数组就像标准的 C 数组声明(即“struct UpdateEntry
条目[20]") 没有任何副作用问题 瑞克斯根. 由于变长数组有
C 中没有明确的语法,尖括号用于它,数组声明是
实际上编译成“结构”。 例如,声明如下:
常量 MAXBULKSIZE = 10000;
常量 MAXENTRIES = 100;
不透明块; /* 最多 10000 个项目 */
内部主机<>; /* 任意数量的项目 */
typedef vldbentry blkentries<100>; /* 首选数组声明 */
被编译成以下结构:
结构{
u_int 散装_len; /* 项目数 */
字符 *bulk_val; /* 指向数组的指针 */
} 大部分;
对于“bulk”数组,同样对于“blkentries<100>”数组,
结构{
u_int blkentries_len; /* 数组中的项目数 */
vldbentry *blkentries_val; /* 指向数组的指针 */
} blkentries;
因此,用户应该注意“神奇”生成的结构条目,例如
数组中的项目数( _len) 和指向数组的指针
( _val) 因为某些条目必须从
客户端/服务器程序。 一个示例过程是:
typedef vldbentry blkentries ;
proc GetBlk (OUT blkentries *vlentries) = VL_GETBLK;
或者,更直接地,
GetBlk(OUT vldbentry vlentries ) = VL_GETBLK;
请注意,虽然最新的方法是可取的,因为人们不必首先使用
typedef 语句(诚然,程序员更喜欢避免使用 typedef),应该
意识到 瑞克斯根 隐式进行结构扩展和 xdr 创建; 所以
用户应该像以前一样了解“vldbentries_val”和“vldbentries_len”字段
(见下面的例子)。
排列 例子 I (至少 可取)
接口配置中的过程声明:
proc ListAttributes(IN vldblistbyattributes *属性,
INOUT blkentries *vldbentries) = VL_LISTATTRIBUTES;
示例客户端代码:
blkentries 条目,*pnt;
entry.blkentries_len = 10; /* 最大 # 返回条目 */
entry.blkentries_val = (vldbentry *)malloc(LEN);
/* 必须设置 */
代码 = VL_ListAttributes(&attributes, &entries);
如果(!代码){
pnt = entry.blkentries_val;
for (i=0; i < entry.blkentries_len; i++, pnt++)
显示_vldbentry(pnt);
/* 确保你释放了分配的空间 */
自由((字符*)entries.blkentries_val);
}
示例服务器代码:
VL_ListAttributes(属性,条目)
{
vldbentry *singleentry = 条目->blkentries_val;
条目-> blkentries_len = 0;
而 (copy_to_vldbentry(&vlentry, singleentry))
singleentry++,vldbentries->entries_len++;
}
尽管这种用于可变大小数组的方法工作正常,但存在一些主要缺点。
数组参数(即上面的 vldbentries)必须声明为 INOUT,因为我们需要
传递预期返回数组的最大长度; 更重要的是,一个大(取决于
“_len”的值)作为结果,垃圾代码块将被传输到服务器
数组的 IN(out) 副作用。 这是一个简单方便的方法,如果
返回的数组大小可以从一开始就预测,当大小相当大时。 这个
方法被列为错误使用(和滥用)的一个例子 瑞克斯根 并且不应该
用过的。
排列 例子 II (可取的 方法)
接口配置中的过程声明(使用上面的示例 I):
proc ListAttributes(IN vldblistbyattributes *属性,
OUT blkentries *vldbentries) = VL_LISTATTRIBUTES;
示例客户端代码:
blkentries 条目,*pnt;
代码 = VL_ListAttributes(&attributes, &entries);
如果(!代码){
pnt = entry.blkentries_val;
for (i=0; i < entry.blkentries_len; i++, pnt++)
显示_vldbentry(pnt);
/* 确保你释放了分配的空间(通过 rxgen)*/
自由((字符*)entries.blkentries_val);
}
示例服务器代码:
VL_ListAttributes(属性,条目)
{
vldbentry *单项;
条目-> blkentries_len = 0;
singleentry = 条目->blkentries_val
= (vldbentry *)malloc(MAXENTRIES * sizeof(vldbentry));
而 (copy_to_vldbentry(&vlentry, singleentry))
singleentry++,vldbentries->entries_len++;
}
这是使用可变大小数组作为输出参数的最佳(也是最简单)方法。
服务器端存根的责任是 malloc() 足够的空间是
自动释放 瑞克斯根 存根; 客户端应该释放分配的空间
此 瑞克斯根-调用存根。
排列 例子 III (已链接 列表)
考虑到以下 3 个声明(可以应用一些优化)
配置文件:
typedef struct single_vldbentry *vldblist;
结构 single_vldbentry {
弗伦特里弗伦特里;
vldblist next_vldb;
};
结构 vldb_list {
vldblist 节点;
};
和 rxgen 过程声明:
LinkedList(IN vldblistbyattributes *属性,
OUT vldb_list *linkedentries) = VL_LINKEDLIST;
示例客户端代码:
vldb_list 链接的vldbs;
vldblist vllist,vllist1;
bzero(&linkedvldbs, sizeof(vldb_list));
代码 = VL_LinkedList(&attributes, &nentries, &linkedvldbs);
如果(!代码){
printf("我们得到了 %d 个 vldb 条目\n", nentries);
for (vllist =linkedvldbs.node; vllist; vllist = vllist1) {
vllist1 = vllist->next_vldb;
display_entry(&vllist->vlentry);
自由((字符*)vllist);
}
}
示例服务器代码:
VL_LinkedList(rxcall,属性,nentries,linkedvldbs);
{
vldblist vllist, *vllistptr = &linkedvldbs->node;
尽管 (...) {
vllist = *vllistptr
= (single_vldbentry *)malloc (sizeof (single_vldbentry));
copy_to_vldbentry(&tentry, &vllist->vlentry);
条目++;
vllistptr = &vllist->next_vldb;
};
*vllistptr = NULL;
}
使用链表有很多优点: 没有任何东西被传递到服务器(参数
是 OUT),不涉及额外的开销,并且调用者不必显式
准备任意返回大小。 一个缺点是调用者有
的责任 malloc() (在服务器上)和免费(在客户端)每个条目(到
避免不必要的核心泄漏)。 另一个缺点是,由于它是递归调用,因此 C
堆栈将相对于列表中的节点数线性增长(因此明智的做法是
如果预期返回大量数据,则增加 Rx LWP 堆栈——默认堆栈大小
是 4K)。 这里的优点应该大于缺点。
注意上面三个数组例子的注释很重要
特别是当它们指的是用户何时应该为
变长数组。 该机制与字符串的处理非常相似,因此您
可能需要查看上面的字符串部分; 注意链表被处理
有点不一样……
其他 例子
下面是一个随机接口文件的缩写版本,它显示了一些常见的
案例。
/* 声明 R.xg 脚本接口使用的所有结构 */
结构AFSFid {
无符号长卷;
无符号长 Vnode;
无符号长唯一;
};
typedef long ViceDataType;
/* 请注意 TEST 仅在
头文件的处理,*.h,文件*/
#ifdef RPC_HDR
#define 测试“标题”
的#else
#define 测试“休息”
#ENDIF
/* 这是标准的 *.xg 规范文件 */
包 AFS_
分割前缀 IN=BEFORE_ OUT=AFTER_;
前缀测试
proc Remove(IN struct AFSFid *Did, IN string volname<64>,
OUT 结构 AFSStatus *Status) = AFS_REMOVE;
DisconnectFS AUX_disconnectFS() = AFS_DISCONNECTFS;
proc GetVolumeInfo(IN 字符串 Vid,
OUT 结构 VolumeInfo *Info) = AFS_GETVOLUMEINFO;
/* 每个配置可以有多个接口 */
包票_
/* 使用“多”功能; 因此 VOTE_Beacon 可以称为
多接收呼叫或作为常规呼叫 */
信标(IN 长状态,长投票开始,
net_version *版本,net_tid *tid)
多 = VOTE_BEACON;
包磁盘_
/* 使用“拆分”功能 */
SendFile(在长文件中,长偏移量,
长,net_version *version)
拆分 = DISK_SENDFILE;
输出 of an 实际 接口 配置
我们将展示一些由生成的实际输出 瑞克斯根 通过遵循一个缩写
实际接口配置。
配置 文件
接口配置文件的内容(vldbint.xg):
包裹VL_
#include "vl_opcodes.h" /* 这里包含操作码 */
%#include "vl_opcodes.h" /* 直接到其他地方 */
/* 当前对影响其他包的参数的限制
(即体积)*/
常量 MAXNAMELEN = 65;
常量 MAXNSERVERS = 8;
常量 MAXTYPES = 3;
/* 单个 vldb 条目的外部(可见)表示 */
结构 vldbentry {
字符名称[MAXNAMELEN];
长卷类型;
长 nServers;
长服务器编号[MAXNSERVERS];
长服务器分区[MAXNSERVERS];
长 serverFlags[MAXNSERVERS];
u_longvolumeId[MAXTYPES];
长旗;
};
typedef struct single_vldbentry *vldblist;
结构 single_vldbentry {
vldbentry vldbentry;
vldblist next_vldb;
};
结构 vldb_list {
vldblist 节点;
};
/* vldb 接口调用 */
CreateEntry(IN 长 Volid,
vldbentry *newentry) = VLCREATEENTRY;
GetEntryByName (IN 字符串卷名,
OUT vldbentry *entry) = VLGETENTRYBYNAME;
GetNewVolumeId(在长颠簸计数中,
输出长 *newvolumid) = VLGETNEWVOLUMEID;
ReplaceEntry (IN long volid,
长voltype,
vldbentry *新条目,
长 ReleaseType) multi = VLREPLACEENTRY;
ListAttributes (IN VldbListByAttributes *属性,
OUT 长 *nentries,
OUT vldbentry 散装货)
= VLLISTATTRIBUTES;
LinkedList(IN VldbListByAttributes *属性,
OUT 长 *nentries,
OUT vldb_list *linkedentries) = VLLINKEDLIST;
我们将只关注 Rx 生成的代码,因为 R 生成的代码 (-R 选项)
很快就会过时。 里面的 Rx 相关调用的详细说明
生成的存根(即 rx_NewCall(), rx_EndCall()),以及有关发生的事情的详细信息
在某些电话中(例如 xdrrx_create()) 请参考 Rx 文档。 打字
“rxgen vldbint.xg”将导致创建四个文件: vldbin.h, xdr变种c,
vldbint.cs.c 和 vldbint变种ss. 下面详细介绍这些文件。
标题 文件 (vldbint.h)
/* 机器生成的文件 -- 不要编辑 */
#include "vl_opcodes.h" /* 直接到其他地方 */
#define 最大名称 65
#定义 MAXNSERVERS 8
#define 最大类型 3
结构 vldbentry {
字符名称[MAXNAMELEN];
长卷类型;
长 nServers;
长服务器编号[MAXNSERVERS];
长服务器分区[MAXNSERVERS];
长 serverFlags[MAXNSERVERS];
u_longvolumeId[MAXTYPES];
长旗;
};
typedef struct vldbentry vldbentry;
bool_t xdr_vldbentry();
typedef struct single_vldbentry *vldblist;
bool_t xdr_vldblist();
结构 single_vldbentry {
vldbentry vldbentry;
vldblist next_vldb;
};
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,
新条目,发布类型), 结束VL_ReplaceEntry(多重调用))
typedef 结构体块{
u_int bulkentries_len;
vldbentry *bulkentries_val;
} 散装;
bool_t xdr_bulkentries();
/* 包的操作码相关的有用统计信息:VL_ */
#定义 VL_LOWEST_OPCODE 501
#定义VL_HIGHEST_OPCODE 506
#define VL_NUMBER_OPCODES 6
请注意,所有结构都会自动进行 typedef,并且所有“const”都被转换为
“#define”。 一些数据结构,例如bulentries,取自procedure params
(来自 ListAttributes 过程)。 因此,在创建存根时应牢记这一点
零碎的 瑞克斯根 (即,使用 -c, -h, -C或 -S 标志)。 另外,一侧
“multi”选项(在“ReplaceEntry”过程中)的效果是生成
上面的“multi_VL_ReplaceEntry”。
XDR 例程 结构 (vldbint.xdr.c)
/* 机器生成的文件 -- 不要编辑 */
#包括
#include "vldbint.h"
#include "vl_opcodes.h" /* 直接到其他地方 */
布尔值
xdr_vldbentry(xdrs,objp)
XDR *xdrs;
vldbentry *objp;
{
如果 (!xdr_vector(xdrs, (char *)objp->name, MAXNAMELEN,
大小(字符),xdr_char))
返回(假);
if (!xdr_long(xdrs, &objp->volumeType))
返回(假);
if (!xdr_long(xdrs, &objp->nServers))
返回(假);
如果 (!xdr_vector(xdrs, (char *)objp->serverNumber, MAXNSERVERS,
大小(长),xdr_long))
返回(假);
如果 (!xdr_vector(xdrs, (char *)objp->serverPartition,
MAXNSERVERS,sizeof(长),xdr_long))
返回(假);
如果 (!xdr_vector(xdrs, (char *)objp->serverFlags, MAXNSERVERS,
大小(长),xdr_long))
返回(假);
如果 (!xdr_vector(xdrs, (char *)objp->volumeId, MAXTYPES,
大小(u_long),xdr_u_long))
返回(假);
if (!xdr_long(xdrs, &objp->flags))
返回(假);
返回(真);
}
布尔值
xdr_vldblist(xdrs,objp)
XDR *xdrs;
vldblist *objp;
{
如果 (!xdr_pointer(xdrs, (char **)objp,
大小(结构 single_vldbentry),
xdr_single_vldbentry))
返回(假);
返回(真);
}
布尔值
xdr_single_vldbentry(xdrs,objp)
XDR *xdrs;
single_vldbentry *objp;
{
如果 (!xdr_vldbentry(xdrs, &objp->VldbEntry))
返回(假);
如果 (!xdr_vldblist(xdrs, &objp->next_vldb))
返回(假);
返回(真);
}
布尔值
xdr_vldb_list(xdrs,objp)
XDR *xdrs;
vldb_list *objp;
{
如果 (!xdr_vldblist(xdrs, &objp->node))
返回(假);
返回(真);
}
布尔值
xdr_bulkentries(xdrs,objp)
XDR *xdrs;
散货 *objp;
{
如果 (!xdr_array(xdrs, (char **)&objp->bulkentries_val,
(u_int *)&objp->bulkentries_len, MAXVLDLBLEN,
大小(vldbentry),xdr_vldbentry))
返回(假);
返回(真);
}
请注意 xdr_bulkentries() 作为程序的副作用自动生成
参数声明。 因此,如果使用相同的多类型参数声明,
然后将创建多重定义的 xdr_* 存根! 我们觉得这是一个更好的选择
拥有 瑞克斯根 程序员处理诸如bulletries_1、bulentries_2之类的类型...
客户端 存根 例程 (vldbint.cs.c)
/* 机器生成的文件 -- 不要编辑 */
#包括
#包括
#包括
#include "vldbint.h"
#include "vl_opcodes.h" /* 直接到其他地方 */
int VL_CreateEntry(z_conn, Volid, newentry)
注册结构 rx_connection *z_conn;
长卷;
vldbentry * 新条目;
{
结构 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, 卷名, 条目)
注册结构 rx_connection *z_conn;
字符 * 卷名;
vldbentry * 条目;
{
结构 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;
如果((!xdr_vldbentry(&z_xdrs,条目))){
z_result = RXGEN_CC_UNMARSHAL;
失败;
}
z_result = RXGEN_SUCCESS;
失败:
返回 rx_EndCall(z_call, z_result);
}
int VL_GetNewVolumeId(z_conn,bumpcount,newvolumid)
注册结构 rx_connection *z_conn;
长颠簸;
长 * 新体积;
{
结构 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;
如果 ((!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)
注册结构 rx_connection *z_conn;
long Volid、voltype、ReleaseType;
vldbentry * 新条目;
{
结构 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, newentry))
|| (!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)
注册结构 rx_call *z_call;
long Volid、voltype、ReleaseType;
vldbentry * 新条目;
{
静态 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, newentry))
|| (!xdr_long(&z_xdrs, &ReleaseType))) {
z_result = RXGEN_CC_MARSHAL;
失败;
}
z_result = RXGEN_SUCCESS;
失败:
返回 z_result;
}
int EndVL_ReplaceEntry(z_call)
注册结构 rx_call *z_call;
{
诠释 z_result;
XDR z_xdrs;
z_result = RXGEN_SUCCESS;
失败:
返回 z_result;
}
int VL_ListAttributes(z_conn,attributes,nentries,bulentries_1)
注册结构 rx_connection *z_conn;
VldbListByAttributes * 属性;
长 * 条目;
散装 * 散装_1;
{
结构 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, 属性))) {
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,属性,nentries,linkedentries)
注册结构 rx_connection *z_conn;
VldbListByAttributes * 属性;
长 * 条目;
vldb_list * 链接条目;
{
结构 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, 属性))) {
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)
结构 rx_call *z_call;
XDR *z_xdrs;
{
长 z_result;
长卷;
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)
结构 rx_call *z_call;
XDR *z_xdrs;
{
长 z_result;
字符 * 卷名 = (字符 *)0;
vldbentry 条目;
如果 ((!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;
if (!xdr_string(z_xdrs, &volumename, 65)) 转到fail1;
返回 z_result;
失败1:
返回 RXGEN_SS_XDRFREE;
}
长 _VL_GetNewVolumeId(z_call, z_xdrs)
结构 rx_call *z_call;
XDR *z_xdrs;
{
长 z_result;
长颠簸;
长新卷;
如果 ((!xdr_long(z_xdrs, &bumpcount))) {
z_result = RXGEN_SS_UNMARSHAL;
失败;
}
z_result = VL_GetNewVolumeId(z_call,bumpcount, &newvolumd);
z_xdrs->x_op = XDR_ENCODE;
如果((!xdr_long(z_xdrs,&newvolumid)))
z_result = RXGEN_SS_MARSHAL;
失败:
返回 z_result;
}
长_VL_ReplaceEntry(z_call,z_xdrs)
结构 rx_call *z_call;
XDR *z_xdrs;
{
长 z_result;
long 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)
结构 rx_call *z_call;
XDR *z_xdrs;
{
长 z_result;
VldbListByAttributes 属性;
长条目;
散装块散装_1;
如果 ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) {
z_result = RXGEN_SS_UNMARSHAL;
失败;
}
z_result = VL_ListAttributes(z_call, &attributes, &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;
if (!xdr_bulkentries(z_xdrs, &bulkentries_1)) 转到fail1;
返回 z_result;
失败1:
返回 RXGEN_SS_XDRFREE;
}
长_VL_LinkedList(z_call,z_xdrs)
结构 rx_call *z_call;
XDR *z_xdrs;
{
长 z_result;
VldbListByAttributes 属性;
长条目;
vldb_list 链接条目;
如果 ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) {
z_result = RXGEN_SS_UNMARSHAL;
失败;
}
z_result = VL_LinkedList(z_call, &attributes, &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();
长 _VL_GetEntryByName();
长 _VL_GetNewVolumeId();
长_VL_ReplaceEntry();
长_VL_ListAttributes();
长_VL_LinkedList();
静态长 (*StubProcsArray0[])() = {_VL_CreateEntry,
_VL_GetEntryByName、_VL_GetNewVolumeId、_VL_ReplaceEntry、
_VL_ListAttributes,_VL_LinkedList};
VL_ExecuteRequest(z_call)
注册结构 rx_call *z_call;
{
国际运营;
XDR z_xdrs;
长 z_result;
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[操作 - VL_LOWEST_OPCODE])
(z_call, &z_xdrs);
返回 z_result;
}
如果过程的操作码序列中存在间隙,则 VL_执行请求()
例程会大不相同(这本来是一个案例陈述
每个程序)。
附注
瑞克斯根 是从 Sun 的 rpcgen 公用事业。 所有的标准 rpcgen's
功能得到完整维护。 注意一些活跃的 rpcgen 不适用的选项
至 瑞克斯根此处未提及的目的(即 -s, -l, -m 选项)和感兴趣的
读者应参考 rpcgen(1) 详情。
当“%#include 使用功能确保您没有任何
瑞克斯根 语言特性(即 %#defines),因为你会在
汇编..
由于这是一个正在进行的项目,因此上述许多内容可能会在没有重大问题的情况下改变/消失
警告。
使用 onworks.net 服务在线使用 rxgen