[英]I need an example to understand Implicit Tagging in ASN.1
事實上,在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
}
這將沒有任何特殊標記,這里只需要通用標簽。 通用標簽不命名數據,它們只是鍵入數據,因此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數據傳輸,甚至考慮為每個標簽保存兩個字節似乎是荒謬的。
使用接受的答案作為編碼示例:
Image ::= SEQUENCE {
Width INTEGER,
Height INTEGER,
Title UTF8String
}
編碼的一個例子是:
內部序列分解為:
如果您具有EXPLICIT OPTIONAL
值:
Image ::= SEQUENCE {
Width [0] EXPLICIT INTEGER OPTIONAL,
Height [1] EXPLICIT INTEGER OPTIONAL,
Title UTF8String
}
編碼序列可能是:
30 15 A1 02 02 02 EE 0C 0E 41 20 66 75 6E 6E 79 20 6B 69 74 74 65 6E
(21字節) 並且內部序列分解為:
A1
02
02
02 EE
750(2字節) 0C
0E
41 20 66 75 6E 6E 79 20 6B 69 74 74 65 6E
“一只有趣的小貓”(14字節)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.