消息设计与开发
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.4 消息类型块

消息的传输格式中,紧接着消息头的,便是消息类型块(Message Type Block)。与消息头相比,虽然同样是消息的宏观描述信息,但是:

· 消息头对所有消息来讲,都是固定长度的,而消息类型块则针对不同响应类型的消息及一些具体细节,长度会有所不同。

· 消息类型块中包括了两种消息类型的信息,一是消息的响应类型,二是消息的功能类型,对请求类消息来讲,还包括消息的远程调用操作类型编号。

对请求类型的消息,其消息类型块中包含以下信息:

· 消息响应类型

· 消息功能类型

· 消息远程调用操作类型

· 消息处理标志

· 消息体长度

对回复类型的消息,其消息类型块中可能包含如下信息:

· 消息响应类型

· 消息功能类型

· 回复错误号

· 回复错误类型

· 回复错误内容

· 回复消息处理标志

· 消息体长度

可见,回复类型的消息类型块比请求类型的消息类型块要多包含一些内容。其实,从后文的内容大家还可以看出,即使同是回复消息,其消息类型块的大小也有区别。

2.4.1 消息响应与功能类型

将消息响应类型与消息功能类型放在一起介绍,是因为虽然它们是两个不同的信息,但却可以用同一个变量来表示。

消息响应类型是指,该消息是请求类型的消息还是回复类型的消息。前文曾经提到过,接收方接收到一个消息,可能是发送方的一个主动请求,也可能是发送方对接收方上次发送请求的回复(这种回复可能是被同步接收,也可能是被异步接收),这就是消息响应类型的概念。很明显,消息的响应类型只用两个状态就可以表达清楚,原理上讲,一个“0”或“1”的bit就可以描述清楚了。

消息功能类型是指,用户会定义不同的消息来完成不同的功能,该消息属于哪一个。由于功能可以有很多,并且可以不断扩充,所以消息功能类型一般用无符号整型的编号来表示(可以采用四个字节整数,就可以容纳足够的功能了)。

在具体代码实现中,如何将消息响应类型与功能类型放在一个变量中表示呢?显然,从表示消息功能类型编号的变量中分出一个bit来表示消息响应类型是可以的,但不难想象的是,消息接收处理的分析过程会稍微复杂一些,并且导致消息功能类型编号无法直接正确展示。由于每一种消息功能类型都需要有请求与回复两种实体存在,所以可以考虑采用偶数编号表示请求类型消息,奇数编号表示回复类型消息的方法,这样一来,一对邻近的奇偶数编号实际上表示了同一种消息功能类型。在第12章中,大家会看到该设计具体的实现细节与流程。

2.4.2 回复消息错误

只有在回复类型的消息类型块中,才有关于“回复消息错误”的信息,它一般包括以下几个方面的内容:错误号,错误类型和错误内容。

1.错误号(Error No)

消息体系设计中,应该对所有可能出现的错误统一编号,每一个错误号都对应一种错误,例如,“网络连接错误”,“消息接收下溢”等,这就是错误号的概念。错误号可以用四个字节的整型数来表示,以留给系统足够的扩展容量。在消息体系中设计错误号,有点类似于UNIX/Linux体系中“errno.h”中定义的各种错误,这样一来,将所有错误规范地管理起来,以达到方便、可控。还有一点,就是系统的本地化(Localization)也会很容易地实现,而不需要检查所有的代码。

2.错误类型(Error Type)

对错误来讲,除了统一的编号,还有一个特性,那就是错误的类型。其实错误类型应该至少有两个大的类别,一种表示该错误的严重级别是“错误”(Error)、“警告”(Warning)还是“提示”(Info);另一种表示该错误真正的类型,包括系统错误(System),应用错误(Application),套接字错误(Socket),IO错误,安全错误(Security),数据库错误(Database)等。

在代码表示中,这两种错误类型既可以用两个变量来表示,也可以采用同一个变量(如4字节)来表示,如用前两个字节表示错误的严重级别,用后两个字节表示错误真正的类型。

3.错误内容(Error String)

错误内容中容纳对该错误的表述信息,是一个字符串。我们知道,在用错误号对错误进行统一管理以后,实际上,可以采用系统函数自动获得某个错误号的描述内容。为什么还要在这里加入“错误内容”这一项呢?这是因为,在消息的传输层,即使是同一类同一个编号的错误,也有很多不同的具体情况和参数需要我们知道,这些信息无法在设计初期完全固化下来,需要在运行时才能完全得到,并且非常重要,因此,在回复消息类型块的设计中加入关于错误内容的元素是非常必要的。

错误内容是一个可变长度的字符串,在消息的代码表示中,虽然可以申请固定长度(错误内容的最大字节长度)栈空间来表示它,但在实际发送(即流化处理)时,却是需要按字符串的实际长度来处理的。实际上,这涉及消息表示中各种数据类型的流化处理问题,会在第3章详细介绍。

上述的错误号与错误类型,虽然在回复消息类型块中用到,但并不只是为其专门设计的。其实,在整个消息体系的各个环节中(发送、接收、处理等)可能遇到的所有其他错误类型,都在该错误号与错误类型的统一管理之下。

最重要的一点是,对不包含错误信息的回复消息,其消息类型块中只有错误号和错误类型两项,并且它们的值均无意义。

2.4.3 消息远程调用操作类型

消息远程调用操作类型(Remote Callback Operation Type)只有在请求类型的消息类型块中才会存在。前文我们说过,一个消息,除了可以承载需要传输的数据以外,还必须具有实现远程调用操作的能力,并且我们可以设计为一种消息功能类型能够承载多种远程调用操作请求,这就是消息类型块中“远程调用操作类型”元素存在的作用与必要性。

对大多数消息机制而言,无论其外在表现上远程调用操作的实现包装与本地函数调用如何类似(甚至形式完全相同),而实际上,在真正的消息体系中都基本如此(因为消息体系要求网络上所有信息与数据都以消息格式传输):远程调用参数通过请求消息体元素传送,执行结果通过回复消息体传送,它们都可以是各种基本数据类型、数组及对象列表的组合。同时,对每一种消息功能类型中的每一个远程调用操作类型,都需要用户根据自己的应用需求自行完成代码实现。至于如何实现这种调用,则是第12章的内容。

同样,在代码表示中,消息远程调用操作类型采用一个基本类型的变量就可以了。

2.4.4 消息处理标志

本请求消息需要等待回复吗?该消息需要比其他消息传输优先级高吗?该消息传输结束后需要自动从内存中清除吗?该请求消息的远程调用操作合法吗?该消息体由哪些主要部分组成(发送与接收时需要处理哪些主要部分)?

消息体系对消息发送/接收以及处理时,需要以上信息,所以消息类型块中专门设计消息处理标志(Flag)以存放以上内容。当然,在代码表示中,消息处理标志也可以采用一个基本类型的变量来表达。

很明显,对请求类型的消息来讲,消息类型块中必须包含消息处理标志,而对回复类型的消息来讲,逻辑便是:有有效标志就包含,没有有效标志(标志的值为零)就不包含。这也正是消息发送与接收时在这一部分的处理逻辑,在第5章大家就可以看到。

2.4.5 消息体长度

读者可能注意到,在消息头中包含了消息数据长度,这里,在消息类型块中,又有一个消息体长度,这是怎么回事呢?其实,消息体长度才是真正用来控制后面接收消息内容的准确依据。而我们知道,消息头中的消息数据长度,可能包含了消息体长度,也可能没包含,更重要的是,仅根据消息头的四项内容,根本无法判断该消息是否真正有消息体存在。而这些,都只有在消息接收机制处理到消息类型块时才能清楚,因此,有必要在消息类型块中加入消息体长度(Message Length)的元素。

从后文我们会知道,消息体长度只是用来控制接收数据的上下限的,实际处理时,并不是一次性地先接收这么长的流数据然后再解释,而应该是按照预定义的消息表示结构(其实便是消息发送/接收的格式协议)来控制发送/接收的过程。因此,消息体长度更多意义上是用来控制消息内容接收大小的边界(主要是上下限),也就是说,如果按照消息表示结构(消息发送/接收的格式协议)接收消息内容中,发现会有超出消息头中消息数据长度的可能性,则应该以此为上限接收,并报该消息接收“上溢”(overflow)错误,然后继续接收;相反,如果发现按照消息表示结构对本消息接收结束后还没有达到该消息数据长度的限制,则应该跳过那些剩下的字节数,并报该消息接收“下溢”(underflow)错误,然后继续接收。因为我们不能因为一个消息的接收错误而影响下一个消息的接收。可以这样讲,消息体长度严格控制了传输字节流中本消息与下一个消息之间的界限,但并不保证消息的正确性。

需要指出的是,对包含错误信息的回复消息来说,其消息类型块中的消息体长度为零,也就是说,该类消息没有消息体存在。

2.4.6 消息类型块的组成标准

从前文所述可以看出,对不同类型消息的不同情况,消息类型块的组成成分不同,并且情况较为复杂。所以这里需要对其进行总结,以便后面第5章中“消息发送与接收”内容的顺利展开。

我们现在知道以下标准:

(1)对请求类型消息,其消息类型块总是由以下元素组成的:

· 消息响应与功能类型

· 消息远程调用操作类型

· 消息处理标志

· 消息体长度

即代码层面可以用四个基本类型的变量表示。

(2)对不包含错误内容的回复消息,包括:

· 消息响应与功能类型

· 错误号(不代表任何错误)

· 错误类型(不代表任何错误)

· 消息处理标志(标志有效时包含,无效时不包含)

· 消息体长度

(3)对包含错误内容的回复消息,包括:

· 消息响应与功能类型

· 错误号

· 错误类型

· 错误内容

· 消息处理标志(标志有效时包含,无效时不包含)

· 消息体长度:值为零,表示消息流化后后面没有消息体

可以看出,对回复类型消息来说,消息处理标志元素只有在其值有意义时才会被包含,准确的说法应该是:在代码表示层面,回复消息类型块的代码单元中应该包含6个基本类型的变量;而在流化后的消息类型块中,则根据消息中有无错误内容,有无消息处理标志两个因素,其组成成分各不相同。