协议设计( Protocol Design )
数据包格式设计( Package Structures Design )
客户端与服务端之间相互通信,有两种形式的数据包参与其中:
· 命令请求数据包( Request package ):发出命令请求
· 命令反馈数据包( Response package ):返回命令执行的结果
命令请求数据包设计
在不同的业务交互中,客户端向服务端发送的数据内容千差万别。为了满足这样的内容描述的需求,我们总结出这些需求的共性,将此类数据包的内容抽象为两部分:
· 命令描述:描述这个数据包是为了进行何种业务操作而发出的。
· 数据描述:描述我们进行上述业务操作所需的具体参数和数据。
命令描述
同步的业务操作通过上述两部分内容即可完成业务操作,但异步的业务操作还需要对数据包进行标注,以知晓是哪一次交互。比如说,在 Windows API 中,某些异步 API 的参数中包含命令的序列号(通常是一个 INT32 类型的数字),命令执行的结果将在 Notification 的消息内容中描述,这一消息中包含同样的序列号,这样,程序员就能将每一次发出的命令请求与这次命令执行的结果对应起来。这种异步操作的 Notification 返回的时间是未知的,甚至得到的 Notification event 的顺序也不一定是先前命令发出的顺序,因此,如果没有这个命令的序列号,程序员将无法将某一次命令请求与这次命令执行的结果相对应。
我们的分布式系统设计同样考虑到了同步请求与异步请求。
对于同步请求,命令描述中仅仅包含命令的名称。
对于异步请求,命令描述中除命令名称外,还包含一个 ID ,这个 ID 要保证在一定的时间内的同一种命令的请求中的唯一性。可以采用 INT32 类型的 ID ,也可以采用 GUID 类型。 INT32 类型的 ID 的优点是除了保证唯一性以外还能附带着表示命令请求的顺序,缺点是需要开发者自行维护 ID 的唯一性。 GUID 类型的 ID 的优点是理论上不可能重复,因此一旦生成即可保证唯一性,缺点是不能像 INT32 ID 那样描述命令请求的顺序(但这个顺序不一定是必需的)。
数据描述
当设计一个通用的服务平台的时候,我们无法预先知晓业务交互中的数据部分是什么样的,幸运的是现代编程语言(如 C# 、 Java 、 C++ )大多支持范型编程,所以,我们无法预先知晓数据的结构,但这不妨碍我们在代码中表述命令请求数据包的数据描述部分,采用一个抽象数据类型即可。
同步命令请求数据包的编程描述
异步命令请求数据包的编程描述
命令请求数据包设计
对于此类数据包,我们依照命令请求数据包的设计,将此类数据包抽象为以下三部分:
- 命令描述:描述这个数据包是为了进行何种业务操作而发出的。
- 数据描述:描述我们进行上述业务操作所需的具体参数和数据。
- 命令反馈:描述数据包被服务端受理的情况。
命令描述
其实就是把“命令请求数据包”中的命令描述复制一遍,原封不动地返回给客户端。
数据描述
在原有“命令请求数据包”中的数据描述中,在原来的数据结构的基础上,改写“输出项”,作为业务操作的返回值 /返回参数。
命令反馈
包含两项:
- 返回码:通常用0代表执行正常/成功,其他值表示错误代码。
- 描述:如果命令执行失败,那么描述里面就尽可能详尽地表述失败的原因。
编程描述(含常用错误代码):
同步命令反馈数据包的编程描述
异步命令反馈数据包的编程描述
数据包序列化( Serialization )
我们采用 JSON进行序列化。
在 C#编程中,我们采用 Json.NET这个类库来实施 JSON序列化。 Json.Net是一个发布在 Codeplex.com上的开源代码库,其许可协议是 MIT。
JSON现在的应用非常广泛,因此开源的类库也非常丰富, Java、 C/C++、 Objective C、 Python、 PHP等实现版本很容易找到。
JSON这种序列化方式和传统的 Web Service中广泛应用的 XML序列化方式相比,有以下优势:
· 序列化后的字符串格式更简单,更短;
· 生成与解析更轻量;
· 与 Web前端的 Ajax技术更兼容,甚至可以被 JavaScript直接识别。
除了 JSON这种序列化方式以外,另外一种同样具备竞争力的序列化方式是 Hessian binary web service protocol(简称 Hessian协议)中采用的序列化方式。对于 Hessian协议,在其官方网站 http://hessian.caucho.com 上,给出了多种语言版本的服务端、客户端开源实现,包括 Java、 .Net/C#、 Python、 PHP、 Objective C等众多版本。
通讯协议( Network Communication Protocol )
当前项目中采用的通讯协议是 HTTP(S)。未来还将补充使用 TCP Socket通讯。
HTTP(S)的优点:
· 编程简单,且在绝大多数情况下不需要程序员自己考虑多线程并发的情况;
· 穿越防火墙的能力好;
HTTP(S)的缺点:
· 只能从客户端主动向服务端发起,无法从服务端主动向客户端 Push消息;
TCP Socket通讯的优点:
· 通讯方式灵活,服务端可主动向客户端 Push消息;
TCP Socket通讯的缺点:
· 编程稍复杂,且在绝大多数情况下需要程序员自己考虑多线程并发的情况;
· 如在公网上应用,很容易被防火墙阻拦;
即使采用 TCP Socket通讯,建议仍然保留 HTTP(S)通讯。可以用 TCP Socket通讯来传递消息通知,而用 HTTP(S)通讯来读取消息内容。
在 HTTP(S)通讯中,我们广泛使用 POST方式来发送和接收数据。服务端的示范代码如下:
以上就是协议设计。