您的位置:首页 > 其它

LP 系列第 2 部分:协议的扩展与改进

2013-12-07 20:56 537 查看
简介: SLP 虽然功能强大,但也有很多不足之处。本文就服务标示符,服务抽象和事件模拟三个方面来改进 SLP 的弱点,并在和原有协议兼容的情况下对协议进行扩展,增强其功能。

发布日期: 2008 年 9 月 08 日
访问情况 : 2498 次浏览
评论: 0 (查看 | 添加评论
- 登录)


平均分 (0个评分)
为本文评分

本系列的第 1 部分文章介绍了 SLP 功能和应用,并把它与目前现存的一些服务发现协议作了比较和优劣分析。从上面的分析来看,SLP 还是有不少缺陷,但是在局域网内的很多应用中,SLP 又确实是首选的解决方案。那么,我们是否可以对 SLP 做一些改进,让其功能更加强大呢?好在 SLP 协议本身的可扩展性非常强,我们可以在协议允许的范围内,对其进行扩展,既丰富了其功能,又使它来兼容标准的规范。本文就这方面问题进行了一些探讨。

服务标示符

UDDI 中使用 uuid 来唯一标示服务实体,类似的,SSDP 中用 usn 来唯一标示服务,但是在 SLP 中并没有这么一个属性。在某些场合中,我们可能想要知道两个属性不同的服务是来自两个不同的服务提供者还是一个服务提供者改变了它的属性,这时,有一个唯一服务标示符就会方便很多。

虽然 SLP 本身没有提供对于唯一服务标示符的支持,我们可以很容易自己构造一个,一个简单的方法是在服务中增加一个标示符属性,但是一个服务在属性的使用上是没有任何限制的,我们并不能保证服务提供者一定会提供这个属性。这时,我们可以利用 SLP 扩展消息来达到这个目的。SLP 扩展消息是由 SLP 协议定义的附在 SLP 标准消息之后的消息。其内容格式由通信双方事先约定,协议并不作要求。我们可以定义一种扩展消息,内容为一个属性列表,表示 SA 在服务中必须提供列表中的属性。当 SA 向 DA 注册时,DA 检查
SA 的属性,如果没有要求的属性,就可以在回复确认消息时附加这个扩展消息,当 SA 收到这则消息时,它就不得不在自己的属性中增加该属性并重新向 DA 注册。这样,我们就可以保证在 DA 中注册的服务都有指定的属性,当然可以包括唯一标示符属性。在没有 DA 的情况下,UA 可以在服务请求中把唯一标示符作为查询条件的一部分,这样虽然不能迫使 SA 添加这项属性,但是也能确保在网络中使用到的服务都有自己的唯一标示符。

这条扩展消息的格式参考如下:

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Extension ID = 0x8000 | Next Extension Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Offset, contd.| Required Attribute List Length| Attribute List/
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

根据 SLP 协议规范,扩展消息 ID 从 0x0000--0x7FFF 为标准扩展消息,0x8000--0x8FFF 为私有扩展,剩下的编号保留。因此这里使用 0x8000 编号作为 ID。后面 24bits 为下一个扩展消息的偏移量,由于 SLP 标准消息后面可以跟多个扩展消息,因此需要该字段来标示下一个扩展在什么地方开始,如果该扩展为最后一条扩展消息,则这项为 0。协议规定,ID 字段和下一个扩展偏移量必须为扩展消息的前两项,后面才是扩展的自定义内容。接下来一项是必要属性列表长度,用于定位随后的属性列表。在这个列表中的所有属性即该
SA 必须提供的属性,列表中的属性只有属性名字,不需要提供值。

由于 SA 在向 DA 注册时通常会注册自己所有的属性,因此当 SA 收到上述扩展时,它自己难以处理这个问题,可以在 SA 端返回一个错误。这时需要人工添加必要的属性后再次向 DA 注册。再次说明,该扩展消息的使用只能保证 SA 的服务有唯一标示符,但是并不能给服务提供唯一标示符。

下面是一个使用这条扩展的示例,其中没有指明的字段值可以是任意合法的字段,假设要求的唯一标示符名字叫 uuid:

SA 向 DA 发送注册消息
Function-ID : 3 (SrvReg,标准注册消息 )

Attr-list: (attr1=12),(attr2=abc)

DA 发现没有 uuid,回复 SA
Function-ID: 5 (SrvAck,标准注册回复消息 )

Error Code: 3 (INVALID_REGISTRATION,协议定义的标准错误 )

Extension-ID: 0x8000

Required attribute list length: 4

Attribute list: uuid

SA 再次注册,加上 uuid 属性
Function-ID : 3

Attr-list: (attr1=12),(attr2=abc),(uuid=347a45cc24f65a4d)

DA 确认
Function-ID: 5

Error Code: 0

SA 顺利注册完毕。

回页首
服务抽象

SOA 浪潮席卷全球,什么是其核心思想?就是 S,即服务。现在的应用系统,从建模,设计到实现,都是以服务为中心展开的。SLP 似乎早已用到了服务的概念,但它毕竟是早于 SOA 好几年出现的。当你现在回过头来审视 SLP 的时候,你会发现其设计思想并非以服务为中心。就像从面向过程到面向对象一样,现在的面向服务是整个的思想体系的转变,SLP 也许在功能上做得很好,但其设计上还是面向过程的。缺少服务描述和服务调用语义已经让 SLP 先天不足,然而在实现服务发现的时候,SLP 还把服务割裂开来,每个部分显式的分别处理,而没有办法把服务抽象为一个整体。仔细阅读规范你会发现,UA
的查询分为服务位置查询,服务类型查询和服务属性查询,DA 或 SA 根据每条查询仅回复位置,类型,属性信息,这些查询都是彼此孤立的,一个服务硬是被割裂成为 3 个部分。当然,这种细粒度的操作在某些时候是非常有用的,可以大大减少通信流量,并增加应用的灵活性。但是,把服务抽象为一个整体,UA 却没有办法通过一次查询得到一项服务的全部信息,这无疑会给使用带来很大的不便。

既然 SLP 标准消息不能做到这些,我们只能再求助于 SLP 扩展消息了。在查询消息中用得最多的,也是协议最核心的就是服务位置查询,简称服务查询。该查询有一个限制是必须针对某一个特定服务类型进行查询,为了不违反现有协议规定,我们只能假设在查询之前 UA 已经明确了服务的类型,因此,我们可以在服务位置查询的标准 SLP 消息下面附上一条扩展消息,说明需要对方提供服务属性。当 DA 或 SA 回复消息时,在标准的 SLP 服务回复消息后面附带扩展,根据要求提供服务的属性。这样,UA 通过一次请求就可以得到有关服务的全部信息了。

附加服务属性的扩展消息格式如下:

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Extension ID = 0x8001 | Next Extension Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Offset, contd.| Attribute List Length | Attribute List/
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

扩展消息编号为 0x8001,UA 在查询时和 SA/DA 回复时都使用这条扩展消息。在 UA 查询时属性列表是空的,回复消息在属性列表中填入属性,示例如下:

UA 发出服务查询消息
Function-ID: 1 (SrvRqst,标准服务查询 )

Extension ID: 0x8001

Attribute List Length: 0

DA/SA 回复
Function-ID: 2 (SrvRply,标准服务回复 )

Extension ID: 0x8001

Attribute List Length: 34

Attribute List: (Attr=123),(uuid=347a45cc24f65a4d)

不过,无论是面向对象还是以服务为中心,主要还在于使用者的思想,工具本身倒是其次。在面向对象刚兴起时,习惯于面向过程开发的人即使用纯面向对象语言 Java 写代码,也仅仅是用了面向对象的语法和格式罢了,其实现的思想仍然是面向过程的。同样,SLP 是否面向服务很大程度上也取决于你怎么用它。在 SLP 实现规范 RFC2614 中定义了 SLP 的实现架构和调用接口,我建议在 Java 实现中再添加一个 Service 类,把规范中 ServiceURL,ServiceType, ServiceLocationAttribute
几个类包含进去,封装成为一个整体,使客户端使用起来也更加方便。

回页首
事件模拟

当你不能完全掌控自己需要的服务时,你就会担心服务的提供者突然的变卦,任何服务属性的变动都有可能影响到你这边应用程序的功能。集中式目录注册中心未必可靠,因为没有办法保证上面的服务信息都是有效的。UDDI 就已经被这个问题困扰好久了。有的应用也许对于它所调用的服务依赖性不强,如果那些服务变得不合适或者失效,只要发现后简单的再找一个新的服务提供者就行。但也有的应用可能难以接受替换服务的间隙所带来的损失,或者难以发现服务属性已发生微妙的变化,它们不得不紧紧盯着服务提供者的一举一动,随时调整自己应对服务的变化。

在这种情况下,使用事件机制就好得多,服务调用者在服务提供者这里注册自己,服务提供者发生变化时,把变化的内容通知调用者,这也是设计模式中的观察者模式所描述的方式。在这点上,UPnP 走在了前面,它的 GENA 就实现了上述的观察者模式。SLP 中的服务生命期可以部分弥补缺少事件机制的不足。当服务生命到期后,如果没有 SA 显式的通知,就默认为服务已经不可用。但是生命服务周期最长为 18.2 小时,在某些应用场景中,18.2 小时已经可以发生太多事情了。因此,我们可以考虑给 SLP 增加事件通知的功能。

事件机制的核心思想仍然是按照上述的观察者模式,不过在 SLP 中要模拟有一点比较麻烦,SLP 的扩展消息虽然适用性很广,但是它一定要附属在某个标准消息之后的,而 SLP 标准消息的语义在协议中都有定义,并没有哪一条是适合用来作为 UA 向 SA 注册自己来用的。因此,可以考虑把该注册消息也变成一条标准消息。好在 SLP 格式中定义消息类型用了 8 个 bit,理论上可以分辨 256 种不同的消息,而在协议中只定义了 11 种,我们自己再附加一些也可以与原来的协议兼容。

在具体的实现上,UA 通过各种查询得知 SA 的信息之后,如果确定要使用某个服务,并对其变化感兴趣时,UA 向该 SA 单播一条注册请求,请求消息的格式如下:

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Service Location header (function-ID = UAReg = 12) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length of URL | URL \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Lifetime |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

其中 Function-ID 为 12,是自定义的消息,表示 UA 向 SA 发送注册。Length of URL 是 URL 的长度,该 URL 表示 UA 用于侦听 SA 的服务变更事件的地址。Lifetime 是请求生存期,单位为秒,UA 只在这个期限内对 SA 的变化感兴趣。一个可能的示例如下:

Function-ID:		12
Length of URL:	15
URL:			12.34.56.78:427
Lifetime:			65535

UA 的注册消息中 lifetime 为 0 也是可能的,说明取消注册。

SA 自己维护一个集合,可以是一个映射表 Map<URL,Date>,SA 向 DA 注册时,向表中添加 DA 的信息,其中 URL 为 DA 的地址,Date 可以取一个非常大的时间,比如 10 年以后,表示永不过期。当 SA 收到 UA 的注册信息时,执行以下逻辑:

If ( lifetime 等于 0)

If ( Map 含有以 URL 为键的记录 )

在 Map 中删除该条记录

else

更新 Date 为当前时间加上 lifetime

if (Map 含有以 URL 为键的记录 )

用新的 Date 覆盖原来 URL 对应的旧 Date 值

else

在 Map 中添加新的键值对(URL, Date)

当 SA 发生变化时,它进行如下处理:

对于 Map 中的每一条记录

if( 该记录的 Date 值小于当前 Date)

在 Map 中删除这条记录

else

给该记录的 URL 发送标准服务注册消息 SrvReg

SrvReg 标准消息中包含了服务的当前所有信息。UA 在收到变更消息后可以及时根据新的服务信息调整自己。这里有一个小小的限制,那就是每个服务必须有自己的服务标示符,这样当它发布变更消息时 UA 或 DA 能确认发布者,可以参考上文关于服务标示符的讨论予以实现。

回页首
系列结语——SLP 的将来

目前,SLP 在局域网内的应用领域仍然占有一席之地,并在一段时期内都是局域网服务发现的一个不错的解决方案。但是其发展前景并不容乐观。它的对手都拥有一整个协议框架,如果 SLP 最终能够发展成为某个协议框架的一部分并得到大型企业和厂商的支持和推动,那么它有可能得到新生。否则的话,随着其它技术的日益发展,SLP 的生存空间将会越来越小,尤其是当硬件 xml 解析器出现并普及后,xml 的处理不再成为性能瓶颈之时,SLP 将最终面临淘汰。

免责声明:

1, 本文所提出的方式方法仅代表作者个人观点。

2, 本文属于原创作品,资料来源不超出参考文献所列范畴,其中任何部分都不会侵犯任何第三方的知识产权。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: