查看源代码 内部形式及其编码
此版本的堆栈符合
- Megaco/H.248 版本 1 (RFC3525),根据实施者指南版本 10-13 更新。
- Megaco/H.248 版本 2,由 draft-ietf-megaco-h248v2-04 定义,根据实施者指南版本 10-13 更新。
- Megaco/H.248 版本 3,由 ITU H.248.1 (09/2005) 定义。
消息的内部形式
我们对二进制和文本编码使用相同的内部形式。我们的 Megaco/H.248 消息的内部形式深受 ASN.1 编码器/解码器使用的内部格式的影响。
- “SEQUENCE OF”表示为列表。
- “CHOICE”表示为大小为 2 的带标签的元组。
- “SEQUENCE”表示为记录,在“megaco/include/megaco_message_v1.hrl”中定义。
- “OPTIONAL”表示为记录中的普通字段,默认值为 'asn1_NOVALUE',表示该字段没有值。
- “OCTET STRING”表示为无符号整数列表。
- “ENUMERATED”表示为单个原子。
- “BIT STRING”表示为原子列表。
- “BOOLEAN”表示为原子 'true' 或 'false'。
- “INTEGER”表示为整数。
- “IA5String”表示为整数列表,其中每个整数是相应字符的 ASCII 值。
- “NULL”表示为原子 'NULL'。
为了完全理解内部形式,您必须获取 Megaco/H.248 协议的 ASN.1 规范,并应用上述规则。请参阅 Erlang/OTP 中 ASN.1 编译器的文档,以了解更多有关 ASN.1 和相应内部形式之间映射的语义的详细信息。
请注意,“TerminationId”记录未在内部形式中使用。它已被 megaco_term_id 记录(在“megaco/include/megaco.hrl”中定义)取代。
不同的编码
Megaco/H.248 标准定义了纯文本编码和二进制编码 (ASN.1 BER),我们已经实现了两者的编码器和解码器。实际上,我们提供了五个不同的编码/解码模块。
在文本编码中,实现者可以选择使用短关键字和长关键字的混合。也可以添加空格以提高可读性。我们使用术语“紧凑”表示使用最短可能关键字且没有可选空格的文本消息,使用术语“美观”表示使用长关键字和缩进样式(如 Megaco/H.248 规范中的文本示例)的格式良好的文本格式。
下面是一个文本消息的示例,以感受美观版本和紧凑版本文本消息之间的差异。首先是美观的、缩进良好的版本,带有长关键字
MEGACO/1 [124.124.124.222]
Transaction = 9998 {
Context = - {
ServiceChange = ROOT {
Services {
Method = Restart,
ServiceChangeAddress = 55555,
Profile = ResGW/1,
Reason = "901 Cold Boot"
}
}
}
}
然后是不带缩进且带有短关键字的紧凑版本
!/1 [124.124.124.222]
T=9998{C=-{SC=ROOT{SV{MT=RS,AD=55555,PF=ResGW/1,RE="901 Cold Boot"}}}}
以及程序员对同一消息的看法。首先构造 ActionRequest 记录列表,然后使用 API 中的一个发送函数发送该列表
Prof = #'ServiceChangeProfile'{profileName = "resgw", version = 1},
Parm = #'ServiceChangeParm'{serviceChangeMethod = restart,
serviceChangeAddress = {portNumber, 55555},
serviceChangeReason = "901 Cold Boot",
serviceChangeProfile = Prof},
Req = #'ServiceChangeRequest'{terminationID = [?megaco_root_termination_id],
serviceChangeParms = Parm},
Actions = [#'ActionRequest'{contextId = ?megaco_null_context_id,
commandRequests = {serviceChangeReq, Req}}],
megaco:call(ConnHandle, Actions, Config).
最后是整个内部形式的打印输出
{'MegacoMessage',
asn1_NOVALUE,
{'Message',
1,
{ip4Address,{'IP4Address', [124,124,124,222], asn1_NOVALUE}},
{transactions,
[
{transactionRequest,
{'TransactionRequest',
9998,
[{'ActionRequest',
0,
asn1_NOVALUE,
asn1_NOVALUE,
[
{'CommandRequest',
{serviceChangeReq,
{'ServiceChangeRequest',
[
{megaco_term_id, false, ["root"]}],
{'ServiceChangeParm',
restart,
{portNumber, 55555},
asn1_NOVALUE,
{'ServiceChangeProfile', "resgw", version = 1},
"901 MG Cold Boot",
asn1_NOVALUE,
asn1_NOVALUE,
asn1_NOVALUE
}
}
},
asn1_NOVALUE,
asn1_NOVALUE
}
]
}
]
}
}
]
}
}
}
提供了以下编码模块
- megaco_pretty_text_encoder - 将消息编码为美观的文本格式,解码美观文本和紧凑文本。
- megaco_compact_text_encoder - 将消息编码为紧凑的文本格式,解码美观文本和紧凑文本。
- megaco_binary_encoder - 编码/解码 ASN.1 BER 消息。此编码器实现最快的 BER 编码器/解码器。推荐的二进制编解码器。
- megaco_ber_encoder - 编码/解码 ASN.1 BER 消息。
- megaco_per_encoder - 编码/解码 ASN.1 PER 消息。注意:此格式不包含在 Megaco 标准中。
- megaco_erl_dist_encoder - 将消息编码为 Erlang 分布格式。它相当冗长,但编码和解码速度非常快。注意:此格式不包含在 Megaco 标准中。
Erlang 分布编码模块的配置
megaco_erl_dist_encoder 模块的 encoding_config 可以是以下之一
[]
- 将消息编码为标准分布格式。它相当冗长,但编码和解码速度非常快。[megaco_compressed]
- 在内部转换后将消息编码为标准分布格式。它不那么冗长,但另一方面,编码和解码的总时间会稍慢(有关更多信息,请参阅性能章节)。[{megaco_compressed, Module}]
- 工作方式与 megaco_compressed 配置参数相同,只是用户在此处提供他们自己的压缩模块。此模块必须实现megaco_edist_compress
行为。[compressed]
- 将消息编码为标准分布格式的压缩形式。它不那么冗长,但另一方面,编码和解码速度会较慢。
文本编码模块的配置
使用文本编码时,实际上有两个不同的配置来控制使用什么软件
[]
- 空列表表示应使用 Erlang 扫描器。[{flex, port()}]
- 解码时使用 flex 扫描器(未针对 SMP 优化)。有关更多信息,请参阅初始配置。[{flex, ports()}]
- 解码时使用 flex 扫描器(针对 SMP 优化)。有关更多信息,请参阅初始配置。
Flex 扫描器是一个 Megaco 扫描器,它被编写为链接驱动程序 (C)。有两种方法可以使其工作
让 Megaco 堆栈启动 flex 扫描器(加载驱动程序)。
为了实现此目的,必须配置 megaco 堆栈
- 将
{scanner, flex}
(或类似)指令添加到 megaco 应用的 Erlang 系统配置文件中(有关详细信息,请参阅初始配置章节)。 - 使用 system_info 函数检索编码配置(其中
Item = text_config
)。 - 使用编码配置(
encoding_config
字段)更新接收句柄。
这样做的好处是 Megaco 处理驱动程序和端口的启动、保持和监督。
- 将
Megaco 客户端(用户)启动 flex 扫描器(加载驱动程序)。
启动 flex 扫描器时,会创建一个到链接驱动程序的端口。此端口必须由进程拥有。此进程不得终止。如果终止,端口也将终止。因此
- 创建一个永久进程。确保此进程受到监督(以便如果它终止,将会被注意到)。
- 让此进程通过调用
megaco_flex_scanner:start/0,1
函数来启动 flex 扫描器。 - 检索编码配置,并在初始化
megaco_receive_handle
时,相应地设置字段encoding_config
。 - 将
megaco_receive_handle
传递给传输模块。
二进制编码模块的配置
使用二进制编码时,需要指定终止 ID 的结构。
[native]
- 跳过转换阶段,即解码后的消息不会转换为我们的内部形式。[integer()]
- 包含每个级别大小(位数)的列表。示例:[3,8,5,8]
。integer/0
- 单字节(8 位)级别的数量。注意:这当前转换为之前的配置。示例:3
([8,8,8]
)。
处理 megaco 版本
有两种方法可以处理不同的 megaco 编码版本。一种是使用动态版本检测(仅对传入消息有效),另一种是在连接信息中显式设置版本。
对于传入消息
动态版本检测
将 megacoreceive_handle 中的协议版本设置为
dynamic
(这是默认值)。
这适用于那些支持部分解码版本的编解码器,目前是 _text_ 和 ber_bin(megaco_binary_encoder
和megaco_ber_bin_encoder
)。
这样,解码器将检测使用哪个版本,然后使用正确的解码器。显式版本
在 megaco_receive_handle 中显式设置实际的协议版本。
从版本 1 开始。当执行初始服务更改并且已协商版本 2 时,将传输进程 (control_pid) 的 megaco_receive_handle 升级到版本 2。请参阅megaco_tcp和megaco_udp。
请注意,如果使用udp
,则同一个传输进程可以用于多个连接。这可能会使升级变得不可能。
对于不支持部分解码版本的编解码器,目前是megaco_ber_encoder
和megaco_per_encoder
,dynamic
将恢复到版本 1。
对于传出消息
- 更新连接信息 protocol_version。
- 发送消息时,可以通过在 Options 中添加项
{protocol_version, integer()}
来覆盖协议版本。请参阅 call 或 cast。
请注意,这不会影响堆栈自主发送的消息。它们使用连接信息的 protocol_version。
编码器回调函数
编码器回调接口由 megaco_encoder
行为定义,请参阅 megaco_encoder
。