
编程语言语言运行时标准库编译器并发编程【免费下载链接】otpErlang/OTP项目地址https://gitcode.com/gh_mirrors/ot/otp点击查看免费下载本文是 Erlang/OTPdiameter应用的入门指南。diameter 是 RFC 6733 定义的 Diameter 协议的完整实现通过字典dictionary接口支持任意 Diameter 应用并完整覆盖 RFC 定义的全部角色客户端client、服务器server与代理agent。读完本文你将理解 service服务、transport传输、application应用与 dictionary字典这四大核心概念掌握用diameter:start_service/2、diameter:add_transport/2与diameter:call/4搭建 Diameter 节点的基本方法并了解如何通过diameterc编译字典文件为自定义 Diameter 应用提供编解码能力。一、diameter 是什么RFC 6733 的 Erlang 实现diameter 应用是 RFC 6733Diameter Base Protocol在 Erlang/OTP 中的实现代码位于仓库的 lib/diameter 目录。它具备两个核心特征协议全覆盖实现 Diameter Base Protocol 的传输连接建立、能力协商capabilities exchange即 CER/CEA 消息、心跳DWR/DWA、断连DPR/DPA以及消息路由等机制应用无关application-agnostic通过字典接口支持任意 Diameter 应用——应用的报文message与 AVP 可以在字典文件中定义并以配置形式输入到 diameter 中无需修改 diameter 本身。因此diameter 并非只支持某一种特定业务如计费或鉴权而是提供了通用的协议框架无论是 RFC 4005 NAS、RFC 4006 信用控制还是自定义的 ETSI 应用都可以通过编写字典文件接入。在文档中需要特别注意一个命名约定diameter小写指 Erlang 应用本身其主 API 定义在 diameter.erlDiameter大写指 RFC 6733 意义上的协议。这一区分在 diameter.erl 的模块文档中被明确强调。二、四大核心概念service、transport、application 与 dictionary一个 Diameter 节点node由以下两层配置组合而成service服务通过接口模块 diameter.erl 中的diameter:start_service/2配置。service 配置定义节点支持的 Diameter 应用以及在传输连接建立时通过能力协商CER/CEA发送给远端对等体peer的能力 AVP如 Origin-Host、Origin-Realm、Vendor-Id 等。transport传输挂在 service 之上通过diameter:add_transport/2添加。transport 提供协议相关的收发功能它实现 diameter 定义的传输接口该接口的规范见 diameter_transport.erl。diameter 应用自带两个传输模块传输模块底层实现源码位置diameter_tcp基于gen_tcp的 TCP 传输diameter_tcp.erldiameter_sctp基于gen_sctp的 SCTP 传输diameter_sctp.erl任何实现了 diameter_transport 接口的模块都可以作为自定义传输模块接入例如 diameter_etcp.erl基于 Erlang 内部进程间传输的 TCP 变体就是一个内置的替代实现。一个典型的 service 通常实现一个Diameter 节点以 Origin-Host AVP 标识。但 transport 本身也可以携带能力 AVP因此一个 service 可以同时实现多个 Diameter 节点——这是构建代理/中继relay场景的关键设计。三、应用application配置回调模块 字典模块service 上定义的每个 Diameter 应用都由两部分构成3.1 应用回调模块application callback module实现 diameter_app 定义的应用接口diameter 通过它通知远端对等体的连接/断开peer_up/3、peer_down/3为出站请求请求对等体选择pick_peer/4、prepare_request/3、prepare_retransmit/3传递入站 Diameter 请求与应答消息handle_request/3、handle_answer/4、handle_error/4。在 diameter_app.erl 中这些回调被归纳为三种风格连接状态通知、出站请求处理链、入站请求处理。所有回调函数都必须被导出A callback module must export all of the functions documented below。回调模块即应用开发者实现 Diameter 节点业务功能的地方。3.2 字典模块dictionary module每个应用还配置一个字典模块负责该应用出站/入站 Diameter 消息的编解码。字典模块通过 diameterc 工具从字典文件生成。diameter 自带 RFC 6733 定义的基础字典字典模块对应应用应用标识diameter_gen_base_rfc3588Diameter Common MessagesRFC 3588 版本0diameter_gen_base_rfc6733Diameter Common MessagesRFC 6733 版本0diameter_gen_accountingDiameter Base AccountingRFC 3588 版本3diameter_gen_acct_rfc6733Diameter Base AccountingRFC 6733 版本3diameter_gen_relayRelay 应用0xFFFFFFFF这些字典的定义文件位于 lib/diameter/src/dict 目录如base_rfc6733.dia、base_accounting.dia、relay.dia、acct_rfc6733.dia等。RFC 6733 原文文本存放在 lib/diameter/doc/standardrfc6733.txt及配套的rfc6733.txt.license。diameter 自身只对两种应用有特定认知Common Messages 应用diameter 自己处理的 CER/CEA、DWR/DWA、DPR/DPA 消息属于该应用Relay 应用其消息和 AVP 没有具体定义因此 diameter 在编解码上对其给予特殊处理。四、service 配置详解4.1 service_opt 与 application_optdiameter:start_service/2的第二个参数是service_opt()列表其中与应用相关的选项类型为application_opt()定义在 diameter.erl{alias, application_alias()}应用在 service 范围内的唯一标识默认取dictionary选项的值。调用diameter:call/4发送请求时用它来指代应用{dictionary, atom()}应用的编解码模块名由字典文件生成{module, application_module()}处理该应用消息的回调模块实现diameter_app接口。除了模块名还可以配置[Mod | ExtraArgs]或#diameter_callback{}记录——后者允许按函数粒度配置回调而非使用整个模块{state, term()}回调的初始状态默认取alias值{call_mutates_state, true|false}pick_peer/4回调是否可以修改应用状态默认false。文档明确警告设为true时pick_peer/4回调会被串行化可能成为性能瓶颈——简单的客户端无碍但服务器/代理需要响应入站请求应避免{answer_errors, callback|report|discard}含解码错误的入站应答消息的处理方式默认discard{request_errors, answer_3xxx|answer|callback}入站请求出现错误除 3007 之外时的处理方式默认answer_3xxx。4.2 能力capability配置capability()类型见 diameter.erl定义能力协商时随 CER/CEA 发送的 AVP 值可同时配置在 service 与 transport 上transport 上的值优先级更高。可配置项包括Origin-Host、Origin-Realm、Host-IP-Address、Vendor-Id、Product-Name、Origin-State-Id、Supported-Vendor-Id、Auth-Application-Id、Inband-Security-Id、Acct-Application-Id、Vendor-Specific-Application-Id、Firmware-Revision。注意每个元组表示一个或多个 AVP 值重复指定相同元组是错误。其中Inband-Security-Id默认是空列表等价于只含 0即 NO_INBAND_SECURITY若指定 1TLS则当对端 CER/CEA 提供 TLS 时会选择升级为 TLS 传输。4.3 一个真实的 service 配置示例仓库自带的示例客户端 client.erl 展示了完整的 service 配置-define(SERVICE(Name), [{Origin-Host, ?L(Name) .example.com}, {Origin-Realm, example.com}, {Vendor-Id, 0}, {Product-Name, Client}, {Auth-Application-Id, [0]}, {decode_format, map}, {restrict_connections, false}, {strict_mbit, false}, {string_decode, false}, {application, [{alias, common}, {dictionary, diameter_gen_base_rfc6733}, {module, client_cb}, {answer_errors, callback}, {call_mutates_state, false}]}]).其中{application, [...]}列表完整对应上文application_opt()的各选项以diameter_gen_base_rfc6733为字典、client_cb为回调模块。start/2的实现展示了diameter:start_service(Name, Opts Defaults)的调用模式见 client.erl。发送请求时则使用diameter:call(Name, common, ACR, [])第二个参数common即alias见 client.erl。五、调用链从 start_service 到 call/4主 API 的完整流程见 diameter.erl 的模块文档diameter:start_service/2创建本地 Diameter 节点及其能力的表示diameter:add_transport/2添加传输能力如{connect, [...]}连接型或{listen, [...]}监听型传输diameter:call/4发送 Diameter 请求并接收应答。入站 Diameter 请求则以回调形式送达 service 配置中指定的diameter_app回调模块。call/4还支持call_opt()选项见 diameter.erl{extra, list()}追加回调参数、{filter, peer_filter()}过滤候选对等体、{peer, peer_ref()}指定发送对等体、{timeout, Unsigned32()}超时毫秒数默认 5000、detach让调用在请求编码后立即返回ok而非等待应答。在底层每个 service 由一个 gen_server 进程表示实现在 diameter_service.erl该模块同时定义了 RFC 3539 watchdog 的状态机initial、okay、suspect、down、reopen见 diameter_service.erl。围绕它还有能力协商进程 diameter_capx.erl、编解码 diameter_codec.erl、对等体管理 diameter_peer.erl、流量/路由 diameter_traffic.erl、监控统计 diameter_stats.erl 等模块共同构成 lib/diameter/src/base 目录下的运行时核心。六、handle_request/3入站请求的处理语义作为应用接口中最核心的回调handle_request/3见 diameter_app.erl接收的#diameter_packet{}包含#diameter_packet{header #diameter_header{}, avps [#diameter_avp{}], msg record() | undefined, errors [Unsigned32() | {Unsigned32(), #diameter_avp{}}], bin binary(), transport_data term()}请求在Relay 应用中收到时msg为undefined否则为请求对应的 recorderrors列出解码过程中发现的错误结果码3xxx 协议错误、5xxx 永久失败用于设置应答中的 Result-Code 与 Failed-AVPtransport_data是传输模块传入的任意 term若回调返回message()则会被保留。回调的返回值决定了应答行为{reply, packet() | message()}向对端发送指定应答{answer_message, 3000..3999 | 5000..5999}发送仅含 Result-Code及 Origin-Host、Origin-Realm、Session-Id必要时 Failed-AVP的应答{relay, Opts}以中继代理角色将请求转发给其他对等体仅 Relay 应用应用标识 0xFFFFFFFF 可用检测到路由环则回 3005 DIAMETER_LOOP_DETECTED无法投递则回 3002 DIAMETER_UNABLE_TO_DELIVER{proxy, Opts}类似relay但只能用于非 Relay 应用{resend, Opts}relay/proxy的中性替代任何应用可用discard丢弃请求不向对端发送应答{eval, Action, PostF}/{eval_packet, Action, PostF}按Action处理后在请求进程中执行PostF。七、自定义应用字典文件与 diameterc要支持自定义 Diameter 应用需要三步见 diameter_dict.md编写字典文件.dia定义应用的消息与 AVP编译生成 Erlang 模块用diameterc工具或m:diameter_make模块配置到 service 上将生成的字典模块作为{dictionary, Mod}选项。7.1 diameterc 用法diameterc 的命令行格式为diameterc [options] file可用选项选项含义-i dir将目录加入代码路径用于指向继承字典编译出的 beam 文件inherits创建的是 beam 依赖而非 erl/hrl 依赖可多次指定-o dir指定生成源码的输出目录默认当前工作目录-E不生成.erl文件-H不生成.hrl文件--name name指定输出模块名--prefix prefix编译前改写输入字典设置name或prefix--inherits arg编译前追加inherits特殊形式--inherits -清除之前的继承、--inherits Prev/Mod将Prev替换为Mod--indirect-inherits启用间接继承特性成功返回 0失败返回非 0。除命令行外diameter_make.erl 提供等价的程序化编译接口。7.2 字典文件格式速览字典文件由若干以开头的 section 组成完整规范见 diameter_dict.md分号;起注释作用id Number定义应用标识Application Id最多一次定义messages时必须提供。出站消息的 Diameter Header 会写入该值入站消息则用它识别对应字典模块name Mod生成模块名默认取文件名去扩展名prefix Name生成 record/常量名的前缀用于避免不同应用间同名消息/AVP 冲突vendor Number Name默认 Vendor-Id用于设置 V 标志的 AVP及所有者说明avp_vendor_id Number为 section 内列出的 AVP 覆盖 Vendor-Idinherits Mod从其他字典模块导入 AVP 定义空列表表示全部导入。文档建议所有字典通常都应从diameter_gen_base_rfc6733继承 RFC 6733 的 AVPavp_types定义 AVP 的名称、代码、类型与标志形如Name Code Type FlagsFlags 为 V/M/P 字符组合或-RFC 6733 已废弃 P 标志custom_types Mod/codecs Mod为指定 AVP 提供自定义编解码模块messages按 RFC 6733 第 3.2 节 Command Code Format Specification 定义应用消息grouped按 RFC 6733 第 4.4 节 Grouped AVP Values 定义 Grouped 类型 AVP 的内容enum Name为 Enumerated 类型 AVP 定义枚举值支持 0x 十六进制前缀end终止解析其后内容被忽略。7.3 消息 record 与数据类型编译字典还会生成一个.hrl文件其中定义了消息与 Grouped AVP 的 record名称带prefix前缀字段即包含的 AVP 名。例如SIP-Deregistration-Reason :: AVP Header: 383 { SIP-Reason-Code } [ SIP-Reason-Info ] * [ AVP ]在空前缀下生成-record(SIP-Deregistration-Reason, {SIP-Reason-Code, SIP-Reason-Info, AVP}).字段值的编码取决于 AVP 的出现次数恰好出现一次时编码为该类型的一个值其他规格可重复、可省略等编码为该类型的列表。RFC 6733 的 AVP 数据格式与 Erlang 类型的对应关系详见 diameter_dict.md中OctetString()在string()与binary()之间的选择由 service 选项string_decode决定Time()仅能编码{{1968,1,20},{3,14,8}}至{{2104,2,26},{9,42,23}}之间的值DiameterURI()支持用#diameter_URI{}record 表示port、transport、protocol 默认分别为 3868、sctp、diameterEnumerated()编码时可用 hrl 中定义的宏。八、传输接口如何接入自定义传输传输模块必须实现 diameter_transport.erl 定义的接口一个启动传输进程的函数以及传输进程与父进程间的消息协议。所有消息形如{diameter, term()}传输进程可能收到{diameter, {send, message() | false}}出站 Diameter 消息{diameter, {close, Pid}}在收到 DPR 的应答 DPA 后终止传输进程的请求{diameter, {tls, Ref, Type, Bool}}能力协商是否选择了 TLS 带内安全Booltrue时连接型进程应发起 TLS 握手、监听型进程应准备接受握手成功后回复{diameter, {tls, Ref}}。入站消息以binary()或#diameter_packet{}形式传给 diameter出站消息的二进制内容在bin字段。这使自定义传输如基于其他协议栈的封装可以无缝接入现有 service 与字典。九、示例代码与测试示例客户端/服务器/中继client.erl、client_cb.erl、server.erl、server_cb.erl、relay.erl、relay_cb.erl、redirect.erl等位于 lib/diameter/examples/code配套的示例字典NAS、CC、EAP、SIP、MIP 等在 lib/diameter/examples/dict测试套件lib/diameter/test 下的 Common Test 套件覆盖了能力协商diameter_capx_SUITE.erl、编解码diameter_codec_SUITE.erl、字典编译diameter_compiler_SUITE.erl、TCP/SCTP 传输diameter_gen_tcp_SUITE.erl、diameter_gen_sctp_SUITE.erl、TLSdiameter_tls_SUITE.erl、中继diameter_relay_SUITE.erl等可作为理解内部行为与验证配置的参考。十、总结diameter 应用以service transport application dictionary四层模型完整实现了 RFC 6733service 定义节点身份与能力transport 提供 TCP/SCTP或任意自定义实现的收发通道application 通过回调模块承载业务逻辑dictionary 以声明式字典文件驱动消息编解码。三者组合即可覆盖客户端、服务器与代理/中继全部角色。继续深入可参阅仓库中的 diameter_dict、diameterc 参考文档以及 diameter_examples.md 指向的示例代码。赞分享编程语言语言运行时标准库编译器并发编程【免费下载链接】otpErlang/OTP项目地址https://gitcode.com/gh_mirrors/ot/otp点击查看免费下载相关推荐Erlang/OTP diameter 应用对 RFC 6733Diameter 基础协议的合规性全面解析Erlang/OTP diameter 应用对 RFC 6733Diameter 基础协议的合规性全面解析 本指南基于 Erlang/OTP 中 lib/d编程语言语言运行时标准库编译器并发编程diameterc 命令详解将 Diameter 字典编译为 Erlang 编解码模块Erlang/OTP diameter 应用diameterc 命令详解将 Diameter 字典编译为 Erlang 编解码模块Erlang/OTP diameter 应用 diameterc 是编程语言语言运行时标准库编译器并发编程Erlang/OTP diameter 字典文件完全指南从 .dia 规范到编解码模块生成Erlang/OTP diameter 字典文件完全指南从 .dia 规范到编解码模块生成 导读 本文是 Erlang/OTP diameter 应用中字典编程语言语言运行时标准库编译器并发编程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考