我需要一个例子来理解ASN.1中的隐式标记

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我需要一个例子来理解ASN.1中的隐式标记相关的知识,希望对你有一定的参考价值。

我一直在阅读以下教程

http://www.obj-sys.com/asn1tutorial/node12.html

你能用一个例子来帮助我理解隐式标记吗?

答案

事实上,在ASN.1标记中,有两个目的:打字和命名。键入意味着它告诉en / /解码器是什么类型的数据类型(它是字符串,整数,布尔值,集合等),命名意味着如果有多个相同类型的字段和一些(或者所有这些都是可选的,它告诉en- /解码器该值是哪个字段。

如果你比较ASN.1,比如JSON,你看看下面的JSON数据:

"Image": {
    "Width":  800,
    "Height": 600,
    "Title":  "View from 15th Floor"
}

你会注意到在JSON中,每个字段总是被明确命名(“Image”,“Width”,“Height”,“Title”)并且显式或隐式地键入(“Title”是一个字符串,因为它的值被包围引号,“宽度”是一个整数,因为它没有引号,只有数字,它不是“null”,“true”或“false”,并且它没有小数句点。

在ASN.1中,这条数据将是:

Image ::= SEQUENCE { 
    Width  INTEGER,
    Height INTEGER,
    Title  UTF8String
 }

这将没有任何特殊标记,这里只需要通用标签。 Universal tags没有命名数据,只是输入数据,所以en- / decoder知道前两个值是整数,最后一个是字符串。第一个整数是Width而第二个是Height不需要在字节流中编码,它是由它们的顺序定义的(序列有固定的顺序,设置不是。在你引用的页面上是正在使用)。

现在更改架构如下:

Image ::= SEQUENCE { 
    Width  INTEGER OPTIONAL,
    Height INTEGER OPTIONAL,
    Title  UTF8String
 }

好的,现在我们遇到了问题。假设收到以下数据:

INTEGER(750), UTF8String("A funny kitten")

什么是750?宽度还是高度?可能是宽度(和高度缺失)或可能是高度(并且缺少宽度),两者看起来都与二进制流相同。在JSON中,每个数据都被命名,因为在ASN.1中它不是。现在单独一种类型是不够的,现在我们还需要一个名字。这就是非通用标签进入游戏的地方。将其更改为:

Image ::= SEQUENCE { 
    Width  [0] INTEGER OPTIONAL,
    Height [1] INTEGER OPTIONAL,
    Title  UTF8String
 }

如果您收到以下数据:

[1]INTEGER(750), UTF8String("A funny kitten")

你知道750是高度而不是宽度(根本没有宽度)。在这里,您声明一个新标记(在这种情况下是一个特定于上下文的标记),它有两个目的:它告诉en- /解码器这是一个整数值(输入),它告诉它是哪个整数值(命名)。

但隐式标记和显式标记之间有什么区别?区别在于隐式标记只是命名数据,en- /解码器需要隐式知道该名称的类型,而显式标记名称并显式键入数据。

如果标记是显式的,则数据将作为以下内容发送:

[1]INTEGER(xxx), UTF8String(yyy)

因此,即使解码器不知道[1]意味着高度,它也知道字节“xxx”将被解析/解释为整数值。显式标记的另一个重要优点是可以在将来更改类型而无需更改标记。例如。

Length ::= [0] INTEGER

可以改为

Length ::= [0] CHOICE { 
    integer INTEGER,
    real    REAL 
}

Tag [0]仍然表示长度,但现在length可以是整数或浮点值。由于类型是明确编码的,因此解码器将始终知道如何正确地解码该值,因此这种变化是向前和向后兼容的(至少在解码器级别,不一定在应用级别向后兼容)。

如果标记是隐式的,则数据将作为以下内容发送:

[1](xxx), UTF8String(yyy)

不知道[1]是什么的解码器将不知道“xxx”的类型,因此无法正确地解析/解释该数据。与JSON不同,ASN.1中的值只是字节。因此“xxx”可以是一个,两个,三个或可能是四个字节,并且如何解码这些字节取决于它们的数据类型,这在数据流本身中没有提供。同样改变[1]的类型肯定会破坏现有的解码器。

好的,但为什么有人会使用隐式标记?总是使用显式标记不是更好吗?使用显式标记时,类型也必须在数据流中进行编码,这将需要每个标记两个额外的字节。对于包含数千(甚至数百万)个标签的数据传输,可能每个字节都很重要(连接速度很慢,数据包很小,数据包损耗很大,处理设备非常弱),双方都知道所有自定义标签,为什么要浪费带宽用于编码,传输和解码不必要类型信息的存储器,存储器和/或处理时间?

请记住,ASN.1是一个相当古老的标准,它的目的是在网络带宽非常昂贵且处理器比现在慢几百倍的时候实现高度紧凑的数据表示。如果你看看今天的所有XML和JSON数据传输,甚至考虑为每个标签保存两个字节似乎是荒谬的。

另一答案

我发现this thread足够清晰,它还包含(小)例子甚至很难,它们是非常“极端”的例子。使用IMPLICIT标签的更“实际”的例子可以在this page中找到。

以上是关于我需要一个例子来理解ASN.1中的隐式标记的主要内容,如果未能解决你的问题,请参考以下文章

转载:深入理解Scala的隐式转换系统

Scala中的隐式转换|理解

Scala的隐式转换

来自 JetpackNavigation 库中通知的隐式深层链接

深入浅出JavaScript中的隐式转换

什么是C语言中的隐式函数声明?