现在的位置: 首页 > 综合 > 正文

ESFramework 开发手册(09) -- ACK机制、同步调用、回复异步调用

2012年12月21日 ⁄ 综合 ⁄ 共 2811字 ⁄ 字号 评论关闭

      正如ESFramework 开发手册(01) -- 发送和处理信息一文中所介绍的,我们在客户端使用ICustomizeOutter接口的Send方法,可以给服务端或其它在线客户端发送自定义信息,那么,如何得知接收方是否已经收到了我们发出的信息了呢?特别是针对一些非常重要的信息,确认对方已经收到是非常重要的。ICustomizeOutter接口的SendCertainly方法就使用了带ACK机制的发送。

1.启用ACK机制

      ACK,即确认的意思。当我们发送一个自定义信息给对方时,对方收到信息后,回复一个ACK给我们,我们接收到了ACK,就知道对方一定收到信息了。

 

    

(1)无论是客户端发送信息给服务端、还是客户端发送信息给其它客户端(ICustomizeOutter接口的SendCertainly方法),或者是服务端发送信息给客户端(ICustomizeController接口的SendCertainlyToLocalClient方法),它们采用的ACK机制的原理是一样的。

(2)当框架接收到需要ACK的信息时,会自动回复ACK给发送方。这是由ESPlus底层自动完成的,应用程序不需要关心。

(3)ESPlus会先回复ACK,然后才会调用处理信息的方法。所以,当发送方接收到ACK回复时,只是意味着接收方已经接收到了信息,并不表示接收方已经处理完了信息。

(4)如果接收方在规定的时间内(默认为30秒)都没有收到ACK,则会抛出超时的异常。当然,在规定的时间内没有收到ACK,并不一定就是接收方没有收到信息,而是有几种可能性:

  • 由于网络慢,导致ACK延迟抵达发送方。
  • 接收方已经掉线。
  • 发送方已经掉线。

(5)SendCertainly方法和SendCertainlyToLocalClient方法采用的是阻塞模型,即只有收到ACK后才会返回,否则一直阻塞当前调用线程。如果既需要ACK机制的发送,又不希望阻塞当前线程,那么,可以异步调用SendCertainlySendCertainlyToLocalClient方法,并通过回调获知是否有超时异常。 

2.信息同步调用

      我们首先介绍一下什么是“信息同步调用”?所谓同步调用,就是在调用线程中返回调用结果。

      以客户端与服务端进行交互时最常见的一种情况为例:客户端发送一个请求给服务端,服务端处理后,返回回复消息。比如像这样,服务端提供一个加法运算的服务,客户端请求加法服务的消息类型为1001,消息体中包含加法运算所需的两个参数;服务端计算完成后给出的回复消息的类型为1002,回复消息的消息体中包含加法运算的结果。

    站在客户端的角度,来看请求消息与应答消息:客户端在调用线程中向服务器发送请求消息,而在接收线程中收到服务器的回复消息,通常,调用线程与接收线程肯定不是同一个线程,所以,从最原始来说,请求消息与回复消息位于不同的线程中。这种模式更像是方法的异步调用异步调用的好处是当前调用线程不会阻塞,而同步调用的好处是编程模型非常直观简单。毫无疑问,在通信框架中,原始的模型就是异步调用模型,而ESFramework也增加了同步调用的机制,使得编程模型更加丰富。使用者可以根据需要使用合适的模型。

      使用自定义信息,我们有几个同步调用的方法,比如ICustomizeOutter接口的Query方法以及ICustomizeController接口的QueryLocalClient方法,这些同步调用的方法都是有返回值的,如果超时没有收到返回的信息,将抛出超时异常。 

      同步调用与带ACK机制的发送采用的是完全相同的模型,我们完全可以使用同步调用来模拟ACK机制,比如,需要确认的信息就使用同步调用发送,接收方在处理同步调用的时候直接返回null,就可以达到同样的效果。 

      但是,同步调用与带ACK机制的发送还是有两点小区别: 

  • 在同步调用中,接收方回复的是对应请求的答案;在带ACK机制的发送中,接收方回复的是ACK
  • 在同步调用中,接收方是处理完信息后才回复;在带ACK机制的发送中,接收方则是先回复ACK,再处理收到信息。

       由于同步调用和带ACK机制的发送都有可能超时抛出异常,所以,我们在程序中应当将其try...catch起来,以防止应用程序抛出未被截获的异常。       

3.回复异步调用

      最后,我们来看看回复异步调用以及其使用场景。

      ICustomizeOutter还有一个重载的Query方法,用于回复异步调用: 

  void Query(string targetUserID, int informationType, byte[] info, CallbackHandler handler, object tag);

      如果调用该Query方法时,则当前线程并不阻塞以等待回复,而是继续向下执行,当接收线程接收到Query的回复信息时,会直接(在接收线程中)回调CallbackHandler委托指向的方法。这就是所谓的“回复异步调用”。

      那么,何时使用回复异步调用了?

      举个很常见的例子。比如,我们的C/S系统的客户端提供一个查询报表的服务,比较直观的方式当然是使用同步调用:客户端点击界面上的“查询”按钮,发出同步调用,等结果返回时刷新界面显示。很简单,是吧?但是这样做有个问题。假设,服务端生成报表比较复杂,需要较长的时间,又或者,网络状况不好,延时比较大,那么当用户点击按钮后,整个界面就“卡死”在哪里了,无法进行其它的操作,直到结果返回之前,界面一直不能操作。这I就严重地影响了用户体验。

      这种情况下,使用回复异步调用就是更好的方式了。当客户端点击界面上的“查询”按钮,采用回复异步调用的模式发出请求,UI线程不会阻塞,而是继续向下执行,所以界面不会出现“卡”的现象。当回复到来时,目标委托方法被回调,在委托方法中通过Control.Invoke将回复的结果数据转发到UI线程进行显示。

      同步调用以及回复异步调用,作为两种互补的方式而存在,具体使用那种模型,需根据您的具体需求来定夺。

 

阅读 更多ESFramework开发手册系列文章

----------------------------------------------------------------------------------------------------------------------------------------------- 

 下载免费版本的ESFramework 以及 demo源码 

关于ESFramework的任何问题,欢迎联系我们:

电话:027-87638960

Q Q:372841921

 

抱歉!评论已关闭.