XDR: External Data Representation

简介

XDR全称为External Data Representation,是一个描述和编码数据的标准。1987年由Sun公司(Sun Microsystems, Inc)发明。

XDR同时是一门语言,主要用来描述协议的数据格式,如RPCNFS等协议就是使用它来描述自身的数据格式。

XDR语言只能用于描述协议的数据格式,不具有编程功能。该语言具有以下特点:

  • 类似于C语言
  • 描述复杂的数据格式时,相比图形描述,其更简洁

XDR语法

分号;

XDR语言中,分号是语句结束符。也就是说,每个语句必须以分号结束。它表明一个逻辑实体的结束。例如:

int a;
int b;
复制代码

保留字

下表列出了XDR语言中的保留字。这些保留字不能作为常量名、变量名或其他标识符名称。

关键字 说明
int 声明整型变量
hyper 声明长整型变量
unsigned 声明无符号类型变量
float 声明浮点型变量
double 声明双精度浮点型变量
enum 声明枚举类型
bool 声明布尔类型
opaque 声明字节流数组类型
string 声明字符串类型
struct 声明结构体类型
union 声明共用体类型
switch 声明共用体类型和用于开关语句
case 开关语句分支
typedef 用以给数据类型取别名
void 声明空值,声明无返回值或无参数的操作

注释

XDR语言有2种注释方法:

  • 使用//注释

    // 单行注释
    复制代码
  • 使用/* */注释

    /* 单行注释 */
    
    /*
      多行注释
      多行注释
      ...
    */
    复制代码

定义变量

定义变量的语法如下:

type-name variable_name = value;
复制代码

XDR数据类型

XDR语言提供了多种数据类型来帮助描述协议的数据格式,下面将会一一展开介绍。

整数类型

XDR语言提供的整数类型有:

类型 存储大小
int(整型) 4字节
unsigned int(无符号整型) 4字节
hyper(长整型) 8字节
unsigned hyper(无符号长整型) 8字节

各个整数类型定义变量的语法如下:

int a;
unsigned int b;
hyper c;
unsigned hyper d;
复制代码

实例演示:

int a = 10;
unsigned hyper d = 10000;
复制代码

浮点数类型

XDR语言提供的浮点数类型有:

类型 存储大小 精度
float(单精度浮点型) 4字节 6 位小数
double(双进度浮点型) 8字节 15 位小数

XDR语言的浮点数类型使用的是IEEE 754标准

各个浮点数类型定义变量的语法如下:

float a;
double b;
复制代码

实例演示:

float a = 1.2;
double b = 3.402823E+38;
复制代码

枚举类型

XDR使用enum定义枚举类型,语法如下:

enum identifier { name-identifier = constant, ... } ;
复制代码

注意:枚举成员的值的类型为int类型;每个枚举成员的值都是唯一的。

实例演示:通过枚举描述红绿蓝3种颜色

enum color_type { 
    RED = 1, 
    GREEN = 2, 
    BLUE = 3 
} ;

color_type color = RED;
复制代码

布尔类型

XDR使用bool定义布尔类型变量,语法如下:

bool identifier;
复制代码

布尔类型只有2个值:FALSE 或者 TRUE

实例演示:

bool a = TRUE;
复制代码

Opaque Data类型

Opaque Data类型主要用来描述字节流数组,它有2种类型:定长和变长Opaque Data类型。

XDR使用opaque声明Opaque Data类型。

定长Opaque Data类型

定长Opaque Data类型定义变量的语法如下:

opaque identifier[n];
复制代码

其中,n是一个整数常量,用于声明数组的长度。

如果n不是4的倍数,程序应对数组进行补齐操作,即在第n个字节后添加r(r 取值范围为:[0,3])个值为0的字节,使得(n+r) mod 4 = 0

定长Opaque Data类型的数据格式如下图所示:

    0        1     ...
+--------+--------+...+--------+--------+...+--------+
| byte 0 | byte 1 |...|byte n-1|    0   |...|    0   |
+--------+--------+...+--------+--------+...+--------+
|<-----------n bytes---------->|<------r bytes------>|
|<-----------n+r (where (n+r) mod 4 = 0)------------>|
                                             FIXED-LENGTH OPAQUE
复制代码

实例演示:

opaque byteBox[128];
复制代码

变长Opaque Data类型

变长Opaque Data类型定义变量的语法如下:

opaque identifier<m>;
// or
opaque identifier<>;
复制代码

其中,m是一个整数常量,用于声明数组的最大长度。

若通过第二种方式(不明确声明数组的最大长度)声明定义变量,则数组默认最大长度为:(2^32) - 1

如果m不是4的倍数,程序应对数组进行补齐操作,即在第m个字节后添加r(r 取值范围为:[0,3])个值为0的字节,使得(m+r) mod 4 = 0

变长Opaque Data类型的数据格式如下图所示:

   0     1     2     3     4     5   ...
+-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+
|        length n       |byte0|byte1|...| n-1 |  0  |...|  0  |
+-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+
|<-------4 bytes------->|<------n bytes------>|<---r bytes--->|
                        |<----n+r (where (n+r) mod 4 = 0)---->|
                                                  VARIABLE-LENGTH OPAQUE
复制代码

其中,数组前4个字节声明了数组的真实长度(有效数据长度)。

实例演示:

opaque byteBox<>;
复制代码

字符串类型

字符串类型主要用来描述ASCII字符数组,它是变长数据类型。

XDR使用string定义字符串类型变量,语法如下:

string object<m>;
//or
string object<>;
复制代码

其中,m是一个整数常量,用于声明数组的最大长度。

若通过第二种方式(不明确声明数组的最大长度)定义字符串类型变量,则数组默认最大长度为:(2^32) - 1

如果m不是4的倍数,程序应对数组进行补齐操作,即在第m个字节后添加r(r 取值范围为:[0,3])个值为0的字节,使得(m+r) mod 4 = 0

字符串类型的数据格式如下图所示:

   0     1     2     3     4     5   ...
+-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+
|        length n       |byte0|byte1|...| n-1 |  0  |...|  0  |
+-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+
|<-------4 bytes------->|<------n bytes------>|<---r bytes--->|
                        |<----n+r (where (n+r) mod 4 = 0)---->|
                                                         STRING
复制代码

其中,数组前4个字节声明了数组的真实长度(有效数据长度)。

实例演示:

string asciiBox<>;
复制代码

数组类型

数组类型主要用来描述已知的数据类型的元素数组,它有2种类型:定长和变长数组类型。

在数组中,每个元素的长度都是4的倍数。

数组每个元素的数据类型相同,但是它们的长度却不一定相同,比如字符串数组。

定长数组类型

定长数组类型定义变量的语法如下:

type-name identifier[n];
复制代码

其中,n是一个整数常量,用于声明数组的长度。

定长数组类型的数据格式如下图所示:

 +---+---+---+---+---+---+---+---+...+---+---+---+---+
 |   element 0   |   element 1   |...|  element n-1  |
 +---+---+---+---+---+---+---+---+...+---+---+---+---+
 |<--------------------n elements------------------->|
                                      FIXED-LENGTH ARRAY
复制代码

实例演示:

string strList[10];
复制代码

变长数组类型

变长数组类型定义变量的语法如下:

type-name identifier<m>;
// or
type-name identifier<>;
复制代码

其中,m是一个整数常量,用于声明数组的最大长度。

若通过第二种方式(不明确声明数组的最大长度)定义变量,则数组默认最大长度为:(2^32) - 1

变长数组类型的数据格式如下图所示:

  0  1  2  3
+--+--+--+--+--+--+--+--+--+--+--+--+...+--+--+--+--+
|     n     | element 0 | element 1 |...|element n-1|
+--+--+--+--+--+--+--+--+--+--+--+--+...+--+--+--+--+
|<-4 bytes->|<--------------n elements------------->|
                                                COUNTED ARRAY
复制代码

其中,数组前4个字节声明了数组的真实长度(有效数据长度)。

实例演示:

string strList<>;
复制代码

结构体类型

结构体类型主要用于描述自定义的数据对象类型。

XDR使用struct定义结构体类型,语法如下:

struct identifier {
   component-declaration-A;
   component-declaration-B;
   ...
};
复制代码

注意:结构体中的成员可以是不同的数据类型,但是成员的长度都应该是4的倍数。

实例演示:

struct msg {
   unsigned int id;
   string body<>;
};
``
复制代码

共用体类型

共用体类型主要用于描述“根据不同条件返回不同数据类型”的数据类型。

XDR使用union switch定义共用体类型,语法如下:

 union switch (discriminant-declaration) {
 case discriminant-value-A:
    arm-declaration-A;
 case discriminant-value-B:
    arm-declaration-B;
 ...
 default: default-declaration;
 } identifier;
复制代码

注意:每个case关键字后面都需要跟着一个合法的判断值。default语句是可选的。

实例演示:根据颜色返回字节流数组或者结构体或者空的数据类型。

union switch (color_type color) {
    case RED:
       opaque results[0];
    case BLUE:
       struct {
       	unsigned int hex;
       } info;
    default:
       void;
 } 
复制代码

Void

XDR使用void代表空。用于描述无值的情况,或者用于描述不接受数据作为输入或不接受数据作为输出的操作。

Constant

XDR使用const为字面量定义一个符号名称,语法如下:

const name-identifier = n;
复制代码

实例演示:在下面的例子中,pi这个符号常量等同于整数常量3.14159。

const pi = 3.14159;
复制代码

Typedef

XDR使用typedef为已声明的数据类型定义一个新标识符。

需要注意的是,在不同场景下,为已声明的数据类型定义一个新标识符会有不同的语法:

  • structunionenum数据类型定义新标识符

    typedef <<struct, union, or enum definition>> identifier;
    复制代码

    实例演示:例如定义bool类型。

    typedef enum {    /* using typedef */
              FALSE = 0,
              TRUE = 1
           } bool;
    
    // or
    
    enum bool {       /* preferred alternative */
      FALSE = 0,
      TRUE = 1
    };
    复制代码
  • 为数组类型定义新标识符

    typedef type_name identifier[n];
    复制代码

    实例演示:定义一个int数组。

    typedef int byteBox[1024]; 
    复制代码

    这时候,下面定义kb变量2种方式都是可以的。

    byteBox kb;
    // or
    int    kb[1024];
    复制代码
  • 为其他数据数据类型定义新标识符

    typedef type_name identifier;
    复制代码

    实例演示:定义一个byte类型。

    typedef int byte; 
    复制代码

Optional-data类型

Optional-data类型用于描述值可能为空(void)的数据类型。它相当于C语言中的指针。

Optional-data类型定义变量的语法如下:

type-name *identifier;
复制代码

使用XDR描述协议

下面将会通过一个小案例演示XDR是如何描述协议的数据格式的。

下图为以太网协议中“帧”的数据格式:

我们现在使用XDR描述进行描述:

struct frame {
	opaque d_mac[6];
	opaque s_mac[6];
	opaque type[2];
	opaque data<1500>;
	opaque fcs[4];
}
复制代码

猜你喜欢

转载自juejin.im/post/5c835ce66fb9a04a037a06ce