关于应用协议的设计

关于应用协议的设计

本文译自:On the Design of Application Protocols

摘要:本文以 ESMTP、FTP、HTTP1.1 协议为例,从 框架、编码、报告、异步、身份验证、隐私 这6个视角描述应用协议的机制,从 可扩展性、效率、简单性、可扩展性、健壮性 这5个视角描述了协议的属性,最后引出设计协议 BXXP(BEEP) 的案例 demo。

在这里插入图片描述

1. 一个酝酿了 19 年的问题

SMTP 接近完美的应用程序协议:它以极简主义的方式解决了一个大而重要的问题。它对于入门级实施来说足够简单,可以适应一两屏代码,并且足够灵活,可以在稳健和竞争激烈的市场中形成非常强大的产品供应的基础。模数一些奇怪的东西(例如,SAML),设计构思良好,最终的规范写得很好并且大部分是独立的。关于良好的应用程序协议设计,几乎没有什么是您无法通过阅读 SMTP 规范学习到的。

不幸的是,有一个小问题:SMTP 最初是在 1981 年发布的,从那时起,已经为 Internet 设计了许多应用程序协议,但并没有进行大量的重用。如果应用程序协议完全不同,您可能会想到这一点,但事实并非如此:尽管实际细节差异很大,但大多数应用程序的功能行为都惊人地相似。

1998 年底,当 Carl Malamud 和我坐下来审查 Blocks 架构时,我们意识到我们需要一个用于交换 Blocks 的协议。传统观点认为,当您需要一个应用程序协议时,有四种方法可以进行:

  1. 找到一个(或多或少)做你想做的现有交换协议;

  2. 在万维网基础设施之上定义一个交换模型(或多或少)做你想做的事;

  3. 在电子邮件基础设施之上定义一个交换模型(或多或少)做你想做的事;或者,

  4. 从头开始​​定义一个完全符合您要求的新协议。

工程师可以对这些方法中的每一种方法的优点进行合理的论证。这是我们遵循的过程…

最吸引人的选择是找到一个现有的协议并使用它。(换句话说,我们宁愿“买”也不愿“制造”。)因此,我们对许多现有的应用程序协议进行了调查,发现它们都不能很好地匹配我们需要的协议的语义。

例如,大多数应用协议都是面向客户端/服务器行为的,强调客户端从服务器拉取数据;与 Blocks 相比,客户端通常从

服务器,但它也可能请求服务器向它异步推送(新)数据。显然,我们可以将 FTP 或 SMTP 等协议改造成我们想要的协议,但是当我们完成所有这些操作时,基本协议和我们的协议将有更多的差异而不是相似之处。换句话说,修改现成的实现的成本与从头开始相当。

另一种方法是使用 HTTP 作为交换协议并定义其上的数据交换规则。例如,IPP(Internet 打印协议)就使用这种方法。基本思想是 HTTP 定义交换数据的规则,然后您定义数据的语法和语义。因为您继承了整个 HTTP 基础结构(例如,HTTP 的身份验证机制、缓存代理等),所以您不必发明(和编写代码!)。或者,相反,您可能认为 HTTP 基础设施太有用了。作为一个额外的好处,如果您决定您的协议在端口 80 上运行,您可以以端口 80 饱和为代价让您的流量通过旧防火墙。

HTTP 有很多优势:它无处不在,为人所熟知,并且有很多工具可用于开发基于 HTTP 的系统。HTTP 的另一个好处是它使用 MIME 来编码数据。

对我们来说不幸的是,即使使用 HTTP 1.1,仍然不是很合适。由于保持与原始 HTTP 的兼容性这一非常理想的目标,HTTP 的框架机制不够灵活,无法支持服务器端异步行为,并且其身份验证模型与其他 Internet 应用程序不相似。

将 IPP 映射到 HTTP 1.1 说明了前一个问题。例如,IPP 服务器应该在作业完成时向其客户端发送信号。由于 HTTP 客户端必须发起所有请求,并且关闭 HTTP 中的持久连接的决定是单方面的,因此 IPP 规范可以做的最好的事情是以非确定性方式指定此功能。

此外,IPP 映射到 HTTP 表明,即使是行为上的细微变化也会产生意想不到的后果。例如,IPP 中的请求通常比许多 HTTP 服务器实现看到的请求大得多——导致许多 HTTP 服务器出现异常(例如,请求有时会被静默截断)。教训是 HTTP 的框架机制在请求/响应模型方面非常严格。

最后,鉴于我们相信 TCP 标头的端口字段不是一个常量 80,我们可以免受想要让我们的流量通过粗心的站点管理员的诱惑。

第三种选择,将协议分层在电子邮件之上,很有吸引力。不幸的是,我们的应用程序的性质包括大量响应时间相对较短的交互。因此,这给我们留下了最后的选择:从头开始定义协议。

首先,我们认为我们的要求虽然比大多数要求严格一些,但可以适合适合未来大量应用程序协议的框架。诀窍是避免厨房水槽的方法。(戴夫·克拉克有句名言:“建筑的作用之一就是告诉你什么不能做。”)

2. 你可以解决任何问题…

…如果您愿意使问题足够小。

我们最重要的一步是将问题限制在具有某些特征的应用程序协议上:

  • 它们是面向连接的;

  • 他们使用请求和响应来交换消息;和,

  • 它们允许异步消息交换。

让我们依次看看每一个。

首先,我们只考虑面向连接的应用程序协议(例如,那些在 TCP 之上工作的协议)。分类法中的另一个分支,无连接,由那些不希望建立和维护可靠流的延迟或开销的分支组成。例如,大多数 DNS 流量的特点是单个请求和响应,两者都适合单个 IP 数据报。在这种情况下,在应用协议本身的传输层之上实现基本的可靠性服务是有意义的。

其次,我们只考虑面向消息的应用程序协议。在我们的词典中,“消息”只是在松耦合系统之间交换的结构化数据。分类法中的另一个分支,紧耦合系统,使用远程过程调用作为交换范例。与面向连接/无连接的二分法不同,松耦合或紧耦合系统的问题类似于连续频谱。幸运的是,边缘相当锋利。

例如,NFS 是一个使用 RPC 的紧耦合系统。在正确配置的 LAN 中运行时,通过 NFS 访问的远程磁盘与本地磁盘几乎没有区别。为实现这一点,紧耦合系统高度关注延迟问题。因此,大多数(但不是全部)紧耦合系统使用无连接 RPC 机制;此外,大多数倾向于作为操作系统功能而不是用户级程序来实现。(在某些环境中,紧密耦合的系统被实现为单一用途的服务器,在专门针对该功能优化的硬件上。)

最后,我们将考虑异步交换消息的应用程序协议的需求。经典的客户端/服务器模型是客户端发送请求,服务器发送请求

回复。如果您将请求视为“问题”,将响应视为“答案”,那么服务器只会回答它提出的那些问题,而不会提出任何自己的问题。我们需要支持更通用的模型,点对点。在这个模型中,对于给定的事务,一个对等点可能是“客户端”,另一个是“服务器”,但对于下一个事务,两个对等点可能会互换角色。

事实证明,客户端/服务器模型是对等模型的一个适当子集:特定应用程序协议规定建立连接的对等方始终充当客户端(发起请求)是可以接受的,并且侦听传入连接的对等方始终充当服务器(发出对请求的响应)。

有相当多的现有应用程序域不符合我们的要求,例如名称服务(通过 DNS)、文件服务(通过 NFS)、支持多播的应用程序(如分布式视频会议)等。然而,有很多应用领域确实符合这些要求,例如,电子邮件、文件传输、远程 shell 和万维网。因此,我们对未来的赌注是,将继续有理由定义适合我们框架的协议。

3. 协议机制

下一步是查看应用程序协议必须执行的任务以及它如何执行这些任务。尽管详尽的阐述可能会确定十几个(或更多)领域,但我们感兴趣的领域是:

  • 框架,说明每条消息的开始和结束是如何定界的;

  • 编码,它说明消息在交换时是如何表示的;

  • 报告,说明错误是如何描述的;

  • 异步,说明如何处理独立交换;

  • 身份验证,说明连接两端的对等点是如何被识别和验证的;和,

  • 隐私,说明如何保护交换免受第三方拦截或修改。

此列表中一个值得注意的缺席是命名——我们将在稍后解释原因。

3.1. 框架

有三种常用的消息定界方法:八位字节填充、八位字节计数和连接爆破。

使用八位字节填充的协议示例是 SMTP。SMTP 中的命令是面向行的(每个命令以 CR-LF 对结尾)。当 SMTP 对端发送消息时,它首先传输“DATA”命令,然后传输消息,然后传输“.”。(点)后跟一个 CR-LF。如果消息包含任何以点开头的行,发送方 SMTP 对等方将发送两个点;类似地,当另一个 SMTP 对等方收到以点开头的行时,它会丢弃该点,如果该行为空,则它知道它已收到整个消息。Octet-stuffing 具有这样的特性,即在开始发送之前不需要将整个消息放在面前。不幸的是,它很慢,因为发送者和接收者都必须扫描消息的每一行以查看是否需要转换它。

使用八位字节计数的协议示例是 HTTP。HTTP 中的命令由一个请求行、后跟标题和正文组成。标头包含一个八位字节计数,指示正文有多大。八位字节计数的属性与八位字节填充相反:

在开始发送消息之前,您需要知道整个消息的长度,但是一旦开始发送或接收,就不需要查看消息的内容。

使用连接爆破的协议的一个例子是 FTP。FTP 中的命令是面向行的,当需要交换消息时,会建立一个新的 TCP 连接来传输消息。octet-counting 和 connection-blasting 都具有消息可以是任意二进制数据的特性;然而,连接爆破方法的缺点是对等点需要通信 IP 地址和 TCP 端口号,这可能会被 NATS 和网络错误“透明地”更改。此外,如果交换的消息很小(比如小于 32k),那么为每条消息建立连接的开销会在数据交换期间造成显着的延迟。

3.2. 编码

有许多用于编码数据的方案(已经提出的编码方案比实际使用的要多得多)。幸运的是,只有少数几个在雷达上大放异彩。

使用 SMTP 交换的消息使用 822 样式进行编码。822 样式将消息分为文本标题和非结构化正文。每个标头都包含一个名称和一个值,并以一对 CR-LF 结尾。额外的 CR-LF 将标头与正文分开。

正是这种结构被 HTTP 用于指示正​​文的长度以用于成帧目的。更正式地说,HTTP 使用 MIME,这是一种 822 样式的应用程序,用于对数据本身(正文)和有关数据的信息(标头)进行编码。也就是说,虽然 HTTP 通常被视为 HTML 的检索机制,但它实际上是一种使用 MIME 编码的对象的检索机制,其中大多数是 HTML 页面或引用对象,例如 GIF。

3.3. 报告

应用协议需要一种在对等点之间传递错误信息的机制。这样做的第一个正式方法是由 SMTP 的“回复代码理论”定义的。基本思想是错误由一个三位数字的字符串标识,每个位置具有不同的含义: 第一个数字:指示成功或失败,永久或暂时;

第二位:表示系统上报情况的部分(如语法分析器);第三位数字:识别实际情况。

SMTP 的操作经验表明,错误条件的范围比使用三位数字符串轻松编码的范围要大(即,对于系统的任何给定部分,您只能报告 10 种不同的出错情况)。因此,提供了一种方便的机制来扩展可以出现在第二个和第三个位置的值的数量。

事实上,到目前为止我们讨论的所有应用程序协议都使用三位数的回复代码,尽管不同应用程序协议的设计者之间的协调比大多数人愿意承认的要少。(IMAP 采用了回复代码理论的变体,它使用不同的语法提供相同的信息。)

除了传送回复代码外,大多数应用程序协议还发送适合人类而非机器消费的文本诊断。(更准确地说,文本诊断适用于能够阅读广泛使用的英语变体的人。)由于回复代码反映了积极和消极的结果,因此对伴随积极回应的文本进行了一些创新用途,例如,转经筒。无论如何,一些更现代的应用程序协议包括诊断文本的语言本地化参数。

最后,自 1981 年引入回复代码以来,提出了两个未解决的批评:

  • 回复代码用于指示操作结果和应用程序协议状态的变化;和,

  • 回复代码不指定关联的文本诊断是发往最终用户、管理员还是程序员。

3.4. 异步

今天很少有应用程序协议允许通过同一连接进行独立交换。事实上,更广泛实施的方法是允许流水线操作,例如,SMTP 中的命令流水线操作或 HTTP 1.1 中的持久连接。流水线允许客户端向服务器发出多个请求,但要求顺序处理这些请求。(请注意,协议需要明确提供对流水线的支持,因为在没有明确指导的情况下,许多实现者

生产出不能正确处理流水线的系统;通常,请求中的错误会导致管道中的后续请求被丢弃)。

流水线是减少网络延迟的有效方法。例如,在没有持久连接的情况下,HTTP 的成帧机制实际上更接近于连接爆破而不是八位字节计数,并且它具有相同的延迟和效率问题。

除了减少网络延迟(流水线效应)之外,异步还通过允许多线程实现处理多个请求来减少服务器延迟。请注意,如果您允许任何形式的异步交换,那么还需要支持并行性,因为交换不一定在单个对等方的同步方向下发生。

不幸的是,当你允许并行时,你还需要一个流量控制机制来避免饥饿和死锁。否则,一组交换机可以独占传输层提供的带宽。此外,如果对等点资源匮乏,那么它可能没有足够的缓冲区来接收消息和死锁结果。

流量控制通常在传输层实现。例如,TCP 使用序列号和滑动窗口:每个接收方管理一个滑动窗口,该窗口指示在收到进一步许可之前可以传输的数据八位字节数。然而,现在是第二只鞋掉落的时候了:细分。如果您进行流量控制,那么您还需要一种分段机制,以便在发送之前将消息分成更小的片段,然后在接收到它们时重新组合它们。

流量控制和分段都会影响协议如何构建框架。在我们将分帧定义为“如何区分每条消息的开始和结束”之前——此外,我们需要能够识别独立的消息,仅在流量控制允许我们发送消息时发送消息,并在消息较大时将它们分段比可用的窗口(或太大而不舒适)。

分段以另一种方式影响成帧——它放宽了八位字节计数要求,即在发送之前您需要知道整个消息的长度。通过分段,您可以在整个消息可用之前开始发送分段。在 HTTP 1.1 中,您可以“分块”(分段)数据以获得此优势。

3.5. 认证

也许由于历史(或歇斯底里)的原因,大多数应用程序协议不进行身份验证。也就是说,它们不验证连接上对等方的身份或正在交换的消息的真实性。或者,如果完成身份验证,则它对于每个协议都是特定于域的。例如,FTP 和 HTTP 使用完全不同的模型和机制来验证连接的发起者。(独立于主流 HTTP,有一个很少使用的变体可以验证它交换的消息。)

很大一部分问题在于,不同的安全机制针对强度、可扩展性或易于部署进行了优化。因此,几年前,开发了 SASL(简单身份验证和安全层)以提供用于验证协议对等方的框架。SASL 让您描述身份验证机制的工作原理,例如 OTP(一次性密码)交换。然后由每个协议设计者指定协议通常如何传送 SASL 交换。例如,解释了 SASL 如何与 SMTP 一起工作。

SASL 潮流的一个显着例外是 HTTP,它定义了自己的身份验证机制。没有理由不能将 SASL 引入 HTTP,尽管为了避免某些竞争条件,必须使用 HTTP 1.1 的持久连接机制。

SASL 有一个有趣的特性,除了显式协议交换来验证身份之外,它还可以使用从下层提供的隐式信息。例如,如果连接在 IPsec 上运行,则在建立 TCP 连接时每个对等方的凭据都是已知的并经过验证。

最后,顾名思义,SASL 不仅可以做身份验证——还可以提供消息完整性或隐私服务,具体取决于所使用的 SASL 机制。

3.6. 隐私

HTTP 是第一个广泛使用的协议,它使用传输安全协议来加密连接上发送的数据。此机制的当前版本 TLS 可用于所有应用程序协议,例如 SMTP 和 ACAP(应用程序配置访问协议)。

原始机制与 TLS 之间的主要区别在于供应而非技术。在最初的配置方法中,一个万维网服务器监听两个端口(一个用于明文流量,另一个用于安全流量);相比之下,按照今天的惯例,执行指定为启用 TLS 的应用程序协议(例如,和)的服务器在单个端口上侦听纯文本流量,并且一旦建立连接,就可以在该连接上使用 TLS面议。

最后,请注意 SASL 和 TLS 都是关于“传输安全”而不是“对象安全”的。这意味着它们专注于为实际通信提供安全属性,它们不为独立于通信交换的数据提供任何安全属性。

3.7. 让我们回顾一下

让我们简要比较一下当今使用的三种主要的面向连接的应用协议的特性:

机制ESMTPFTPHTTP1.1
框架填料爆破计数
编码822风格的二进制MIME
报告3位3位3位
异步流水线none流水线和分块
身份验证SASL用户/密码用户/密码
隐私SASL或TLSTLS(nee SSL)

请注意,FTP 和 HTTP 使用的用户名/密码机制完全不同,只有一个例外:两者都可以称为 “用户名/密码”机制。

这三种选择具有广泛的代表性:随着更多协议被考虑,模式得到加强。例如,POP 使用八位字节填充,而 IMAP 使用八位字节计数,等等。

4. 协议属性

当我们设计一个应用程序协议时,有一些我们应该关注的属性。

4.1. 可扩展性

设计良好的协议是可扩展的。

因为很少有应用程序协议支持异步,所以一个常见的技巧是程序打开多个同时连接到一个目的地。从理论上讲,这可以减少延迟并增加吞吐量。事实上,传输层和服务器都将每个连接视为应用程序协议的独立实例,这会导致问题。

在传输层方面,TCP 使用自适应算法随着网络条件的变化有效地传输数据。但是 TCP 学习的内容仅限于每个连接。因此,如果您有多个 TCP 连接,则必须多次经历相同的学习过程——即使您要连接到同一台主机。这不仅会给网络带来不必要的流量高峰,因为 TCP 在建立连接时使用慢启动算法,程序仍然会看到额外的延迟。为了解决应用程序协议中缺乏异步性导致实施者草率使用传输层这一事实,现在为网络协议提供了越来越复杂的功能,例如 RED。此外,还正在考虑修改 TCP 实现以减少并发学习的建议,例如。

在服务器方面,必须针对相同的资源分派和(可能)验证每个传入连接。因此,服务器开销的增加基于建立的连接数,而不是远程用户的数量。同样的公平问题也出现了:当一个用户可以在服务器上造成任意数量的连接时,服务器很难在每个用户的基础上分配资源。

要考虑的可扩展性的另一个重要方面是客户端和服务器的相对数量。(即使在点对点模型中也是如此,其中点可以同时充当客户端和服务器角色。)通常,客户端点比服务器点多得多。在这种情况下,功能需求应该从服务器转移到客户端。原因是服务器可能与多个客户端交互,这种功能转变使其更容易扩展。

4.2. 效率

精心设计的协议是有效的。

例如,虽然可以提出一个令人信服的论点,即八位字节填充比八位字节计数导致更优雅的实现,但经验表明八位字节计数消耗的周期要少得多。

遗憾的是,我们有时不得不牺牲效率来满足其他属性。例如,822(和 MIME)使用文本标头。如果我们愿意限制可以使用的标头名称和值,我们当然可以为标头定义更有效的表示。在这种情况下,可扩展性被认为比效率更重要。当然,如果我们设计的是网络协议而不是应用程序协议,那么我们会使用具有不同边缘的剃刀进行权衡。

4.3. 简单性

设计良好的协议很简单。

这里有一个很好的经验法则:一个设计不佳的应用程序协议是一种在其中做一些基本的事情和做一些复杂的事情一样“具有挑战性”的协议。简单的事情应该很容易做,困难的事情应该更难做。原因很简单:痛苦应该与收获成正比。

另一个经验法则是,如果一个应用程序协议有两种方法来做完全相同的事情,那么在应用程序协议设计的基础架构中的某个地方就会出现问题。

希望简单并不意味着头脑简单:设计良好的东西可以解决问题域中的所有问题,甚至是边缘的麻烦问题。使设计简单的原因在于它以一致的方式做到这一点。通常,这会导致优雅的设计。

4.4. 可扩展性

设计良好的协议是可扩展的。

尽管应用程序协议设计者很聪明,但很可能会有无法预料的问题需要应用程序协议来解决。因此,提供可用于添加功能或自定义行为的挂钩非常重要。这意味着该协议是进化的,并且必须有一种方法可以让实现反映进化路径中的不同步骤来协商将使用哪些扩展。

但是,避免落入可扩展性陷阱很重要:所提供的挂钩不应针对不成熟的未来需求。最重要的是,钩子应该很简单。

当然,好的设计对最大限度地减少可扩展性的需求大有帮助。例如,SMTP虽然最初没有扩展框架,但经过十年的实践,才改变了其优秀的设计。相比之下,如果不围绕扩展概念构建,设计糟糕的协议(如 Telnet)将无法运行。

4.5. 健壮性

设计良好的协议是健壮的。

稳健性和效率常常是矛盾的。例如,虽然默认值对于减少数据包大小和处理时间很有用,但它们往往会鼓励实施错误。

与直觉相反,Postel 的健壮性原则(“发送的内容保守,接受的内容自由”)经常会导致部署问题。为什么?当一个新的实现最初被部署时,它很可能只会遇到现有实现的一个子集。如果这些实现遵循稳健性原则,那么新实现中的错误可能不会被发现。然后,新的实施会看到一些,但没有广泛部署。几个新的实现重复这个过程。最终,不太正确的实现遇到了比初始实现集更不自由的其他实现。读者应该能够弄清楚接下来会发生什么。

因此,协议中的显式一致性检查非常有用,即使它们会增加实现开销。

5. BXXP框架

最后,我们开始付诸行动:这就是我们所做的。

我们定义了一个名为 BXXP(Blocks eXtensible eXchange Protocol)的应用程序协议框架。它是一个“框架”而不是一个应用程序协议的原因是我们提供了前面讨论的所有机制而没有实际指定交换的消息类型。因此,当其他人需要一个需要面向连接的异步交互的应用程序协议时,他们可以从 BXXP 入手。然后他们有责任定义应用程序协议的最后 10%,正如我们所说,这部分所做的是“有用的工作”。

那么,BXXP 是什么样子的呢?

机制BXXP
框架计数,带预告片
编码MIME,默认为 text/xml
报告3 位数和本地化的文本诊断
异步通道
身份验证SASL
隐私SASL 或 TLS

5.1. 分帧和编码

BXXP 中的框架看起来很像 SMTP 或 HTTP:有一个标识框架开头的命令行,然后是一个 MIME 对象(标题和主体)。与 SMTP 不同,BXXP 使用八位字节计数,但与 HTTP 不同的是,命令行是您查找有效负载大小的地方。最后,在 MIME 对象之后有一个尾部以帮助检测帧错误。

实际上,BXXP 的命令行有很多信息,它告诉你:

  • 此框架中的消息类型;

  • 消息中是否有比这个框架中的内容更多的内容(一个延续标志);

  • 如何区分此帧中包含的消息与其他消息消息(消息编号);

  • 有效负载出现在滑动窗口中的位置(序列号)以及该帧的有效载荷中有多少个八位字节;

  • 应用程序的哪一部分应该获取消息(一个通道数字)。

(命令行是文本的,以 CR-LF 对结尾,并且参数由空格分隔。)

因为你需要知道所有这些东西来处理一个帧,所以我们把它们都放在一个易于解析的位置。您可能会设计出一种更高效的编码,但命令行只是框架的一小部分,因此您不会从优化中获得太多反弹。此外,由于帧是 BXXP 的核心,帧格式有几个一致性检查可以捕获大多数编程错误。
(序列号、八位字节计数和尾部的组合允许非常稳健的错误检测。)

另一个技巧是在标头中:因为命令行包含所有的框架信息,标头可能包含最少的 MIME 信息(例如 Content-Type)。但是,通常标题是空的。那是因为 BXXP 默认有效载荷是 XML 。
(实际上,一个带有二进制传输编码的“Content-Type:text/xml”)。

我们选择 XML 作为默认值,因为它为嵌套的文本表示提供了一种简单的机制。(唉,822 风格的编码不容易支持嵌套。)按照设计,XML 的本质并未针对紧凑表示进行优化。这没关系,因为我们专注于松散耦合的系统,此外还有高效的 XML 解析器可用。此外,还有大量轶事经验——我们将强调“轶事”一词——如果您有任何类型的压缩(在链路层或在加密期间),那么 XML 编码会很好地压缩。

尽管如此,XML 的使用可能是 BXXP 中最具争议的部分。毕竟,周围有更有效的表示。我们同意,但真正的问题不是效率,而是易用性:有很多人理解 XML,并且有很多 XML 工具。重建这种社会基础设施的痛苦远远超过设计新代表的任何好处。那么,如果“make”选项太贵,那么除了 XML 之外,还有什么我们可以“购买”的吗?嗯,有 ASN.1/BER(开玩笑)。

在使用 ASN.1 的 SNMP 早期,出现了同样的问题。最后,工作组同意将 ASN.1 用于 SNMP 是不言而喻的,但这并不是因为有人认为 ASN.1 是最有效的,或者最容易解释的,甚至是很受欢迎的。ASN.1 被赋予了公理地位,因为工作组决定不打算在未来三年内向开发人员社区解释替代编码方案。

因此——我们为诉诸教条而道歉——使用 XML 作为 BXXP 中最受欢迎的编码方案是不言而喻的。

5.2. 报告

我们使用 3 位错误代码,并带有本地化的文本诊断。(每个对等方都指定了首选的语言顺序。)

此外,对消息的回复被标记为肯定或否定。这使得指示成功或失败变得容易,并允许接收方在失败时想要进行的解析量上有一定的自由度。

5.3. 异步

尽管吸取了 SMTP 和 HTTP 的经验教训,但在设计 BXXP 的异步功能时并没有太多的现场经验可以依赖。
(实际上,1998 年有几项与应用层框架相关的努力,例如 ,但似乎都没有实现轨道。)

所以,这就是我们所做的:在“通道”的上下文中交换帧。每个通道都有一个关联的“配置文件”,它定义了通过通道交换的消息的语法和语义。

通道既为 BXXP 提供了可扩展性机制,也为并行性奠定了基础。还记得 BXXP 框架命令行中的最后一个参数吗?获取消息的“应用程序部分”由通道号标识。

配置文件是根据“配置文件注册”模板定义的。该模板定义了配置文件的识别方式(使用 URI)、交换的消息类型以及这些消息的语法和语义。当你创建一个频道时,你会识别一个配置文件,并且可能会附带你的第一条消息。如果频道创建成功,你会得到一个肯定的回应;否则,你会得到一个否定的回应来解释原因。

了解通道如何提供可扩展性机制的最简单方法也许是考虑建立会话时发生的情况。每个 BXXP 对等方立即在通道 0 上发送问候语

识别每个支持的配置文件。(通道 0 用于通道管理——它是在会话打开时自动创建的。)如果你想要传输安全,你要做的第一件事就是创建一个协商传输安全的通道,一旦创建了通道,你告诉它做它的事情。接下来,如果您想要进行身份验证,则创建一个执行用户身份验证的通道,并且在创建通道后,您告诉它忙。此时,您创建了一个或多个数据交换通道。这个过程称为“调优”;一旦你调整了会话,你就开始使用数据交换通道来做“有用的工作”。

成功启动的第一个频道有一个与之相关的技巧:当您要求启动该频道时,您可以指定一个与之相关的“服务名称”。这允许具有多种配置的服务器根据客户端的建议选择一个。(一个有用的类比是 HTTP 1.1 的“主机:”标头。)如果服务器接受“服务名称”,则此配置将用于会话的其余部分。

为了允许并行,BXXP 允许您同时使用多个通道。每个通道串行处理消息,但对不同通道的处理顺序没有限制。因此,在多线程实现中,每个通道都映射到它自己的线程。

当然,这是最普遍的情况。由于某种原因,实施者可能无法支持这一点。因此,BXXP 允许在发送消息时进行正面和负面回复。因此,如果您想要经典的客户端/服务器模型,客户端程序应该简单地拒绝服务器发送的任何新消息。这有效地限制了来自服务器的任何异步消息。

当然,我们现在需要提供分段和流量控制的机制。对于前者,我们只是在框架的命令行中放置一个“继续”或“更多”标志。对于后者,我们引入了“传输映射”的概念。

这意味着 BXXP 没有直接定义它如何位于 TCP 顶部。相反,它列出了传输服务如何支持 BXXP 会话的一系列要求。然后,在单独的文档中,我们定义了如何使用 TCP 来满足这些要求。

第二个文档几乎是在说“直接使用 TCP”,只是它引入了一种流量控制机制,用于在单个 TCP 连接上多路复用通道。我们使用的机制与使用的机制相同

通过 TCP(序列号和滑动窗口)。它已被证明,并且可以通过 BXXP 的最小实现来轻松实现。

从实现的角度来看,流量控制的引入是一种负担——尽管 TCP 的机制在概念上很简单,但实现者必须非常小心。例如,应该解决诸如优先级、队列管理等问题。无论如何,我们认为允许应用程序内流并行的好处是值得的。(此外,我们相信很少有应用程序实现者会直接编写 BXXP 框架的代码——相反,我们希望他们使用实现 BXXP 的第三方包。)

5.4. 认证

我们使用 SASL。如果您使用通道成功进行身份验证,那么该会话中的每个对等点都有一个用户身份(即,身份验证是按会话进行的,而不是按通道进行的)。此设计决策要求每个会话都对应于一个用户,而不管该会话上打开了多少个频道。这很重要的一个原因是它允许服务供应,例如服务质量(例如,如中)以每个用户的粒度来完成。

5.5. 隐私

我们使用 SASL 和 TLS。如果您成功地使用通道完成了传输安全协商,那么该会话上的所有流量都是安全的(即机密性是针对每个会话的,而不是针对每个通道的,就像身份验证一样)。

我们定义了一个用于启动 TLS 引擎的 BXXP 配置文件。

5.6. 我们遗漏的东西

我们有意排除了大多数应用程序协议共有的两件事:命名和授权。

命名被排除在框架之外,因为在 URI 之外,没有一个普遍接受的命名框架。在我们看来,这仍然是每个应用程序协议的特定领域问题。也许 URI 在特定问题域的上下文中是合适的,也许不合适。因此,当应用程序协议设计者定义他们自己的配置文件来完成“有用的工作”时,他们将不得不自己处理命名问题。BXXP 提供了一种用于识别配置文件并将其绑定到通道的机制。由您来定义配置文件和使用频道。

同样,授权被明确排除在框架之外。我们见过的每一种授权方法都使用名称来标识主体(即目标和主体),因此如果一个框架不包括命名,它就不能很好地包括授权。

当然,应用程序协议确实必须处理命名和授权——这是应用程序协议设计者在定义用于 BXXP 的配置文件时要解决的两个问题。

5.7. 从框架到协议

那么,您如何使用 BXXP?首先,将其称为“BEEP”,而不是“BXXP”(我们稍后会解释原因)。

首先,获取 BEEP 核心规范并阅读它。接下来,定义您自己的配置文件。最后,获得一个开源 SDK(C、Java 或 Tcl)并开始编码。

BEEP 规范本身定义了几个配置文件:通道管理配置文件、SASL 配置文件系列和传输安全配置文件。此外,还有第二个规范解释了 BEEP 会话如何映射到单个 TCP 连接。

有关使用 BEEP 定义的应用程序协议的完整示例,请查看 reliable syslog 。本文档举例说明公式:应用程序协议 = BEEP + 1 个或多个配置文件 + 授权政策 + 供应规则(例如,使用 SRV RR)

6. BXXP现在是BEEP

我们于 1998 年秋季开始研究 BXXP。IETF 于 2000 年夏季成立了 BXXP 工作组。尽管该工作组对 BXXP 进行了一些改进,但最值得注意的有以下三个方面:

  • 负载默认值是“application/octet-stream”。这主要是为了线路效率——如果您关心线路效率,那么您可能不会使用“text/xml”……

  • 支持一对多交换(客户端发送一条消息,服务器发回许多回复)。

  • BXXP 现在称为 BEEP(更多可笑的可能性)。

7. 安全考虑

请参阅 Section 的第 8 节,了解与 BEEP 相关的安全问题的讨论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值