英语法语西班牙文

OnWorks 网站图标

rxgen - 云端在线

通过 Ubuntu Online、Fedora Online、Windows 在线模拟器或 MAC OS 在线模拟器在 OnWorks 免费托管服务提供商中运行 rxgen

这是 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.cvldbint变种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


免费服务器和工作站

下载 Windows 和 Linux 应用程序

  • 1
    Gin 网络框架
    Gin 网络框架
    Gin 是一个非常快的 Web 框架
    用 Golang 编写,最多可以执行
    快了 40 倍,这要归功于它的
    类似马提尼的 API 和自定义版本
    http路由...
    下载 Gin Web 框架
  • 2
    CEREUS Linux
    CEREUS Linux
    CEREUS LINUX 和 MX LINUX 控制器
    各种不同的写入方式。 这是
    也可以获取的应用程序

    https://sourceforge.net/projects/cereu...
    下载CEREUS LINUX
  • 3
    任务教练
    任务教练
    任务教练 - 你的友好任务
    经理。 任务教练是免费开放的
    源待办事项管理器。 它长出了
    对其他程序的挫败感
    处理复合...
    下载任务教练
  • 4
    HyperSQL数据库引擎(HSQLDB)
    HyperSQL数据库引擎(HSQLDB)
    HSQLDB是一个关系数据库引擎
    用 Java 编写,带有 JDBC 驱动程序,
    符合 ANSI SQL:2016。 一个小的,
    快速、多线程引擎和服务器
    与记忆...
    下载 HyperSQL 数据库引擎 (HSQLDB)
  • 5
    蜡染恢复
    蜡染恢复
    由 Batik 开发的 Project Recovery
    来自印度尼西亚的恢复团队合作,这
    蜡染恢复是蜡染的衍生物
    官方 TWRP 已由
    开发...
    下载蜡染恢复
  • 6
    TightVNC的
    TightVNC的
    TightVNC 是 VNC 的改进版本,
    很棒的免费远程桌面工具。 这
    改进包括带宽友好
    “紧”编码,文件传输
    在...
    下载 TightVNC
  • 更多 ”

Linux 命令

Ad