10039.用C语言实现H.323协议中的ASN.1过程

http://www.bjx.com.cn/files/wx/sjtx-2/15.htm
 
CH.323ASN.1
  怀 
  (
 : ASN.1广H.323ASN.1C语言
: ASN.1 H.323 PER compiler  
  在一个由不同厂家生产的计算机构成的环境中,由于机器硬件和软件配置的不同,在数据表示(诸如安符编码、数值表示、字长)方面往往存在差异。为使厂家各产品之间互通互连,我们必须消除这些差异,应具有一套独立于计算机硬件和软件环境的外部数据表示格式,并通过对其编解码实现。抽象语法表示ASN.1(ITU - T rec.X.680|ISO/IEC8824-1)及它的基本编码规则BER(ITU-T Rec. X.690|ISO/IEC8825-1)和紧缩编码规则PER(ITU-T Rec.X.691|ISO/ IEC8825-2)即充当了这一角色,被许多应用层协议所使用,使不同系统之间的互连、互通成为可能。
  在开发IP电话的H.323协议时,由于网关之间的视频、音频数据和控制消息要通过互联网进行传输,而网关产品可能是不同厂家生产的,软、硬件环境各不相同。因此采用了ASN.1语法表示,传送的格式是基于ASN.1的PER(packed encoding rules)编码格式的比特流。  

、ASN1toC
1.
  目前实现ASN.1编解码的工作有软件和硬件两种实现方案。硬件编解码器虽然处理速度快,但是维护、升级等都很困难。软件编解码虽然可以找到已经实现了的通用的工具,但是由于其通用性而导致占用资源增多,对于我们开发专门的H.323协议,存在着很多冗余。因此我们的办法是采用软件实现,借鉴通用工具的同时去除其中的冗余性,达到精简的目的。
  用结构化的C语言开发H.323协议栈时,遇到的第一个问题就是如何把H.225 、H235和H.245等协议给出的用ASN.1表示的各个消息结构用程序能够“看懂”的数据结构表示出来。通过比较我们不难实现ASN.1数据结构到C语言数据结构之间的映射,映射关系可参见文献[1]。从ASN.1表示的数据类型到编程语言表示的数据类型进行映射时,要遵循如下的规则:映射后的结构应当具有足够的信息进行编码或者应当具有足够的域存放解码后的数据,考虑的因素还有实现的复杂度及优化存储等。
  协议X.680定义了ASN.1一些基本的数据类型,协议X.690给出了如何对这些数据类型进行BER(basic enco-ding rules)编码,协议X.691给出了如何对这些数据类型进行PER编码,由基本的数据类型可以结合成不同的结构,对某个协议中出现的ASN.1数据类型的编码有两种方案2。我们采用对每种新出现的数据类型都生成一个编码和解码函数的方法,利用ASN.1编译器自动完成对.asn文件的编译工作。用编译器对.asn文件编译之后,生成.h和.c两个文件。.h文件声明编译之后生成的C数据类型和编/解码函数,.c文件用来实现编/解码函数。
2.ASN1-C
(1)实现编译器要做的准备工作在实现编译器之前,我们要做以下的工作:
  a.进行数据结构的映射,实现ASN.1类型到C类型的翻译工作,并存在头文件中。遵循规则如前所述,ASN.1基本类型见协议X.680。
  b.编制运行时函数库(Run-time Library Function),包括BER运行时库函数、PER运行时库函数以及运行时公用库函数。BER运行时函数库包括X.680中规定的基本的数据类型的BER编码函数,PER运行时函数库包括其PER编码函数,公用函数库包括跟踪、诊断、打印、出错信息处理以及其它为前两个库函数所用的函数等。这一步设计的库函数留出API接口供程序调用,用户当然可以自己调用这些函数进行数据的编码。在这里,对这些函数的调用可自动由编译器生成的.c文件调用。
(2)进入编译器的实现过程
  以上的工作做好之后,就可以实际进行编译器的实现了。ASN.1编译器的编译过程包括:初始化、处理模块定义头、一个一个地分析协议中指定的数据类型、生成编译表和C代码。
  具体地说编译过程主要包括了三次扫描。

  ①第一次扫描分析语法,向用户报告语法错误和生成编译表
  以ASN.1模块定义为输入,对其进行语法分析,如果发现了语法错误,编译器会停止并报告错误以及出错的行号,为了简化数据类型编/解码器的产生,这一阶段将输入的模块的多层次结构化类型进行串行化。它定义每个子结构为一个新的类型,并给其赋予名字,然后这个结构化的类型可以用这些新赋的子类型的名字在各个相应的子域上重新定义,将所有的结构填入编译码。
  ②第二次扫描分析编译表,向用户报告未定义的数据类型,生成包含用C语言定义的数据类型头文件
  编译表在编译过程中起到了很重要的作用,它是对数据进行详细描述的一张表,位于内存,使我们很容易对它进行处理。这样一个纪录的列表列出了第一次扫描之后产生的所有数据类型。在ASN.1文件中,由于类型声明的顺序是随机的,因此如下的工作要事先做好:
  ·当遇到一个尚未实际定义的“已定义”数据类型时,要为它分配一条纪录框架,以供填充。
  ·当遇到一个新的类型指定时,有必要检查一下该纪录类型框架是否已分配。
  ·第一次扫描之后生成编译表时,要注意应当使其具有恰当的数据类型声明顺序,以适合C语言编译器的要求。
  ③第三次扫描根据编译表产生C文件,以实现头文件定义的编码和解码函数
  生成的C文件实现头文件定义的编码和解码函数。这一部分代码具有很强的规律性,它们遵从一个模式,例如首先判断该结构有没有扩展项,然后判断有没有可选项(OP-TIONAL)或默认项(DEFAULT),以进行相应的处理,具体如何处理见X.690(BER),X.691(PER),处理完这些之后,就是实际地逐次对各个子结构进行编码,一直到该结构的结束,如果想要得到一些调试信息或者出错信息的话,还可以加入其它的调试函数或错误处理函数,这些函数都可以从运行时函数库中得到。
(3)进一步的优化工作
  到了这一步,编译器实现的任务基本完成了,程序已经有了可用的协议数据结构,也可以进行编、解码的工作了。但是上面所做的工作是所有的ASN.1到C编译器都要做的工作,而我们针对的是H.323协议,这一特殊性导致除了对数据进行通用的处理之外,我们还可以针对开发协议本身做一些优化工作。H.323网关的嵌入式软件要求我们的程序尽可能减少对资源的占用,我们对已经生成的代码的优化,根本目的也在于此,即减少占用内存或CPU的时间。
  优化工作可以根据从底层到顶层应用的顺序分三层进行优化,它们分别是编译级、协议级和用户级,下面分别予以介绍。
    编译级:采用合理的方式在编译过程中即进行优化。

  这一步优化是对ASN表示编译成C语言表示时所做的优化,仅以一例说明。我们注意到,一般的ASN到C的编译工具对一个ASN结构中的可选项(OPTIONAL)和默认项(DE-FAULT)的处理是在其生成的C结构内的最前面有一个结构,这个结构的各个子域即是各个可选项或默认项的代表,它以布尔型来表示在协议数据单元中,该项是否出现。布尔型的长度等于整型,当有m个可选项时,这个结构所占的字节数为4m个(U-NIX系统中),这无疑比较浪费开销。编译时可考虑将这一结构用比特来表示,这样只要用一个字节表示有几个可选项,另一个(或几个)字节的各个比特为0或者1,来表示每个可选项存在与否。协议级:针对特定的H.323协议而进行的优化。
  这一步优化的依据来源于H.323本身,协议数据单元很多结构的子域内有很多重复的结构,对这些结构的编码与其按部就班地编,不如事先将其编码编好,到时查表即可。速度是以占内存为代价的,所以这样处理的结构不宜太多,仅对一些编码时间较长的结构适合,比如OBJECT IDENTI-FIER结构等。
    用户级:针对具体用户的应用所做的简化。
这一步可根据用户的具体应用,做很多的精简工作。比如用户在做企业级的网关时,由于某个原因而不做H.235协议,H.235的ASN部分就不用写入。再比如说,如果程序是专门用于某个公司的,那么和生产厂商有关的信息如Endpoin tTyp e,也可按协议级所说的方法进行简化。
  ASN.1编解码过程是网络通信协议的必要组成部分,本文针对H.323协议ASN .1过程的解决提出了一些基本的原则,以及实践中应当注意的一些问题。虽然针对的是H.323协议,但是这个过程同样适合其它网络协议ASN.1过程的解决,在处理上是很类似的一个过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值