RAR 协议全称为Request - Action - Response 协议,是一种互联网请求-动作-反馈简单模式通信协议。是基于TCP 协议基础上的远程通信协议。应用于远程数据请求和远程操纵。 其设计的初衷是为互联网领域和工控领域提供高并发的解决方案。
第一,传统TCP通信
对于TCP协议,其缓存数据类型为byte类型。当客户端将数据发给服务端时,服务端并不能识别这些byte 代表何意。这就需要提前约定,比如第几位,什么值代表什么意思。 这种交互的优点是速度快简单直接。 示意图:
client -> |44|15|32|54|21| -> Server
缺点也非常明显,程序的可读性非常差。 需要文档非常充分,将每个值都事先定义好。 开发的过程中,需要不断查文档,以了解信号具体含义。 如果换了另一个人开发,上手非常缓慢,开发效率低。程序的耦合度高,不利于团队协作。
第二,http 协议
http 协议是应用层协议,其通信效率低于TCP,但是由于它事先定义好了通信双方的协议格式,服务端拿到数据后,则按照事先约定好的协议解析为http请求对象。经过引擎处理解析后,返回一个response。一个简单的http报文如下:
GET / HTTP/1.1 Host: 127.0.0.1:3372 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Accept: text/html,application/xhtml+xml,application/xml; Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
HTTP协议的请求方法有GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT。常用的为get 和post。 当使用get时, 数据被置于请求头部url 位置。 比如
http://www.baidu.com/s?wd=http
当有多个参数时,用&分割不同参数。示例:?a=test&b=whoami
其参数也只能是字符串等基本类型,传输到服务端后,解析为基本类型。如果你想传输一个json 对象,必须使用post 方法。此时,json对象被至于请求体内。
但是,post方法需要两次通信。
第一次,客户端将请求头部信息发给服务端。类似发了一个get 方法包,服务器返回200, 客户端再次发送剩余body部分。 例子:
{"name":"tom","sex":"male"}
post方法只所以这样去做,有其根源。http协议本身就是事先定义好的基本格式。服务端拿到报文只能按照约定好的格式解析。当你发一个json对象给它时,它无法识别这一格式。 所以,只能先发http的头部信息。服务器先拿到请求的url,进行路由,根据路由所指向的具体方法,获取函数的输入参数的类型,来确定post过来的数据格式是什么。然后,才能解析出来json 对象。 这实际上,从客户端到服务器端,有两次序列化和反序列化。对于TCP协议一次完成的动作,它需要两次才能完成通信。
虽然它程序的可读性很高,均以对象进行传输,但是它牺牲了通信效率,降低了服务器的负载能力。
第三,RAR 协议- 探针协议
探针协议吸收了两种通信协议的优点,又做了改进。首先,它传输的数据为json对象。在编程时,可以直接反序列化为一个object。避免了简单的TCP 协议耦合性高的缺点。 同时,它只需要一次传输,就可以把数据完全发送到服务端。示例:
{"_":23,"~rq":true,"~s":51456,"~_":"29f551ee-ddcb-4a52-9cec-43f7518ba137","~ip":null,"~l":null,"n":"tom","p":null}
它的实现原理就是,率先对报文的头部进行部分解析。比如本例中,上来先解析,{"_":23,
获取其索引值,根据其索引值寻找相应的请求对象和动作对象。然后,将数据反序列化为请求对象,调用请求对象进行处理,返回一个结果给客户端。
它率先解析头部的索引,可以形象的比喻为探针。故而名为探针协议。
第四:基于探针协议的编程
使用探针协议,必须先获取探针协议框架。就如同mvc 架构一样,你只需要书写服务器端的action 和客户端的请求响应。而关于远程通信部分以及序列化部分,由框架完成。 这样开发人员可以完全关注于业务逻辑,而不是通信机制。
其服务器端action 示例:
[SysAct(Act = SysAction.Close, RequestType = typeof(Request), ReturnType = typeof(Response))] class CloseAction: ActionBase { public override Response Execute() { Session.Clear(); Response response = new Response(); response.Code = SysAction.Close; return response; } }
必须在类的头部,添加一个attribute, 指明action类的索引值,请求的类型,返回类型。 必须重载execute 方法。这样,服务器端就可以根据这些设定,构建其一张表,把action 索引和具体类,以及请求和响应的相关类串联起来。
其客户端示例如下:
NetUIClient.Main.CallServer<SysSearchResponse>(SysAction.SysSearch, request, (response) => { if (response != null && response.Result != null) { //todo something } });
定义一个request, 将索引和request 直接丢给server, 拿到response 后执行lambda 函数。
对于服务器端和客户端,需要都知道action类的索引,request 类和response 类。 对于服务器端,还需要知道响应的动作action类。
第五,面向对象的编程和面向过程的编程
在工控领域,特别是机床的自动化控制。可以将机床的每一个动作抽象为action。 而每一个action就是一个类对象,这个类对象只有execute 方法会被系统调用。机床的一次完整的操作由若干个动作完成。从编程上来讲,就是多个action 依次执行。也就是客户端按顺序将请求依次发往服务端,服务端完成动作返回结果。至此,将面向对象的编程和面向过程的编程实现完美统一。