0.作业要求
使用ASN.1编写一个数据结构。数据结构自己考虑。
分别使用asn1c、JavaAsn1Compiler等对这个数据结构进行编译。
使用c/java/python进行编码,并存储,而后用另外一种编程语言进行解码,比如,用C编码,可以用java或者python解码。
对“要求一”中的数据结构,使用protobuffer实现一次。这里不强制要求不同的语言实现编码和解码。
1.使用ASN.1编写一个数据结构
数据结构如下所示:
由两个INTEGER型和两个OCTET STRING型的数据构成
RectangleModule1 DEFINITIONS ::=
BEGIN
Rectangle ::= SEQUENCE {
height INTEGER,
width INTEGER,
author OCTET STRING,
title OCTET STRING
}
END
2.分别使用asn1c、JavaAsn1Compiler等对这个数据结构进行编译
asn1c -fnative-types rectangle.asn1
由于编译出的文件过多,下图只截取部分编译结果
htkz@htkz:~/Desktop/ASN1/ASN.1$ asn1c -fnative-types rectangle.asn
然后是java
htkz@htkz:~/java_asn1/src$ java -jar JAC.jar -d ~/java_asn1/src/jac_test -p rectangle rectangle.asn1
3.编程实现编码与解码
本次编程选择使用Java进行编码,然后使用python进行解码
3.1 Java编码
在之前使用的JavaAsn1Compiler编译出来的类中添加如下代码,来给数据数据结构赋值
public static void main(String []args) {
// 创建输出流变量
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
BerOutputStream out = new BerOutputStream(outStream);
// 对rec这个类进行赋值
// 赋值结果为rec(author= b’1234′, title = b’1234′, height = 1011, width = 21)
Rectangle rec = new Rectangle();
byte[] name = new byte[4];
name[0] = ‘1’;
name[1] = ‘2’;
name[2] = ‘3’;
name[3] = ‘4’;
rec.author.setValue(name);
rec.title.setValue(name);
rec.height.setValue(1011);
rec.width.setValue(21);
// 对输出变量进行编码
try {
rec.encode(out);
System.out.println(out.toString());
}catch (java.io.IOException e1){
System.out.println(e1);
}
// 将编码后的结果写入test_rec文件,此时文件是二进制数据
File f = new File(“test_rec”);
try{
OutputStream outFile = new FileOutputStream(f);
try{outFile.write(outStream.toByteArray());}
catch (java.io.IOException e2){
System.out.println(e2);
}
}catch(java.io.FileNotFoundException e1){
System.out.println(e1);
}
PS:java文件的运行需要导入JAC.jar的包,这个包就在之前使用的JavaAsn1Compiler_3.0中,具体路径如下
JavaAsn1Compiler_3.0/lib/JAC.jar
程序运行之后会在代码路径下生成编码后的二进制文件test_rec_2,这个文件中的数据为rec(author= b’1234′, title = b’1234′, height = 1011, width = 21),之后使用python对这个文件进行解码
3.2 python解码
首先在python中定义相应的类rectangle.py
from pyasn1.type import univ, namedtype
class Rectangle(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType(‘height’, univ.Integer()),
namedtype.NamedType(‘width’, univ.Integer()),
namedtype.NamedType(‘author’, univ.OctetString()),
namedtype.NamedType(‘title’, univ.OctetString()),
)
PS:本来这个类按照pyasn1官方文档的方法,应该是使用asn1ate 这个工具来直接识别asn文件获取类的解构,就像前面的asn1c和 JavaAsn1Compiler一样,但是我git clone下来之后发现asn1ate这个工具还是有一点问题,就懒得调试了,没有用它。而是直接在pyasn1-modules中找了样例,直接自己手写了一个。
之后就是解码相关文件的代码了,相当简洁
from pyasn1.codec.der.decoder import decode as der_decoder
from rectangle import Rectangle
if __name__ == “__main__”:
text = file = open(‘test_rec’, ‘rb’).read()
result = der_decoder(text, asn1Spec=Rectangle())
print(result[0].prettyPrint())
4.protobuffer实现
首先根据上述数据结构编写proto文件如下
message Rectangle {
required int32 height = 1;
required int32 width = 2;
optional string author = 3;
optional string title = 4;
}
下载protobufgitfer
git clone https://github.com/google/protobuf.git
之后使用如下指令生成python、java、cpp文件
protoc –proto_path= rectangle.proto –python_out ./
protoc –proto_path= rectangle.proto –cpp_out ./
protoc –proto_path= rectangle.proto –java_out ./