В тегах ASN.1 фактически есть две цели: печатать и называть.Типизирование означает, что он сообщает энкодеру / декодеру, какой это тип данных (это строка, целое число, логическое значение, набор и т. Д.), А именование означает, что если имеется несколько полей одного типа и несколько (или все они) являются необязательными, они указывают en / decoder, для какого поля это значение имеет значение.
Если вы сравниваете ASN.1, скажем, с JSON, и смотрите следующие данные JSON:
"Image": {
"Width": 800,
"Height": 600,
"Title": "View from 15th Floor"
}
Вы заметите, что в JSON каждое поле всегда имеет явное имя («Изображение», «Ширина», «Высота», «Заголовок») и имеет явную или неявную типизацию («Заголовок» - этострока, так как ее значение заключено в кавычки, "Width" является целым числом, потому что в нем нет кавычек, только цифр, это не "null", "true" или "false", и у него нет десятичного периода).
В ASN.1 этот фрагмент данных будет:
Image ::= SEQUENCE {
Width INTEGER,
Height INTEGER,
Title UTF8String
}
Это будет работать без каких-либо специальных тегов, здесь требуются только универсальные теги. Универсальные теги не называют данные, они просто вводят данные, поэтому en / decoder знает, что первые два значения являются целыми числами, а последнее - строкой.То, что первое целое число является шириной, а второе - высотой, не нужно кодировать в потоке байтов, оно определяется их порядком (последовательности имеют фиксированный порядок, наборы - нет. На странице, на которую вы ссылались наборы,используется).
Теперь измените схему следующим образом:
Image ::= SEQUENCE {
Width INTEGER OPTIONAL,
Height INTEGER OPTIONAL,
Title UTF8String
}
Хорошо, теперь у нас проблема.Предположим, что получены следующие данные:
INTEGER(750), UTF8String("A funny kitten")
Что такое 750?Ширина или Высота?Может быть Width (и Height отсутствует) или может быть Height (и Width отсутствует), оба будут выглядеть так же, как двоичный поток.В JSON это будет понятно, поскольку каждый фрагмент данных назван, а в ASN.1 - нет.Теперь одного типа недостаточно, теперь нам также нужно имя.Вот где в игру вступают неуниверсальные теги.Измените его на:
Image ::= SEQUENCE {
Width [0] INTEGER OPTIONAL,
Height [1] INTEGER OPTIONAL,
Title UTF8String
}
И если вы получите следующие данные:
[1]INTEGER(750), UTF8String("A funny kitten")
Вы знаете, что 750 - это высота, а не ширина (просто нет ширины).Здесь вы объявляете новый тег (в данном случае специфичный для контекста), который служит двум целям: он сообщает en / decoder, что это целочисленное значение (типирование), и сообщает ему, какое целочисленное значение (naming).
Но в чем разница между неявной и явной пометкой? Разница в том, что неявная пометка просто именует данные, en / декодер должен неявно знать тип для этого имени, в то время как явные теговые имена и явно вводят данные .
Если тегирование является явным, данные будут отправлены как:
[1]INTEGER(xxx), UTF8String(yyy)
, так что даже еслидекодер не знает, что [1] означает «высота», он знает, что байты «xxx» должны быть проанализированы / интерпретированы как целочисленное значение.Другое важное преимущество явного тегирования заключается в том, что тип может быть изменен в будущем без изменения тега.Например,
Length ::= [0] INTEGER
можно изменить на
Length ::= [0] CHOICE {
integer INTEGER,
real REAL
}
. Тег [0] по-прежнему означает длину, но теперь длина может быть целым числом или значением с плавающей запятой.Поскольку тип кодируется явно, декодеры всегда будут знать, как правильно декодировать значение, и, следовательно, это изменение является прямой и обратной совместимостью (по крайней мере, на уровне декодера, не обязательно обратной совместимостью на уровне приложения).
Если тегированиенеявно, данные будут отправлены как:
[1](xxx), UTF8String(yyy)
Декодер, который не знает, что такое [1], не будет знать тип «xxx» и, следовательно, не сможет правильно проанализировать / интерпретировать эти данные,В отличие от JSON, значения в ASN.1 являются просто байтами.Таким образом, «xxx» может быть одним, двумя, тремя или, может быть, четырьмя байтами, и то, как декодировать эти байты, зависит от их типа данных, который не предусмотрен в самом потоке данных.Также изменение типа [1] наверняка сломает существующие декодеры.
Хорошо, но зачем кому-то использовать неявные теги? Разве не лучше всегда использовать явные теги? При явном тегировании тип также должен быть закодирован в потоке данных, и для этого потребуется два дополнительных байта на тег. Для передач данных, содержащих несколько тысяч (может быть, даже миллионов) тегов и где, возможно, учитывается каждый отдельный байт (очень медленное соединение, крошечные пакеты, высокая потеря пакетов, очень слабые устройства обработки) и где обе стороны в любом случае знают все пользовательские теги, зачем тратить пропускную способность , память, время хранения и / или обработки для кодирования, передачи и декодирования ненужной информации типа?
Имейте в виду, что ASN.1 является довольно старым стандартом и предназначался для обеспечения очень компактного представления данных в то время, когда пропускная способность сети была очень дорогой, а процессоры - в несколько сотен раз медленнее, чем сегодня. Если вы посмотрите на все передачи данных XML и JSON на сегодняшний день, даже смешно думать о том, чтобы сэкономить два байта на тег.