好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

.Net Remoting与WCF通讯比较

.Net Remoting与WCF通讯比较

.Net Remoting与WCF实现Server与Client通讯比较

2011-11-12 20:26 by tyb1222, 779 visits,  收藏 ,  编辑

  .Net Remoting是微软早前推出的一项分布式通讯技术框架,在.Net架构的程序中有着比较广泛的应用。在WCF中,已经集成了Remoting的技术。不过,他们有着很多相同的概念,如:信道(Channel)、代理(Proxy)、寄宿(host)等。在如今仍有一些分布式系统应用中运行着由Remoting技术构建的系统。本文将描述在服务端与客户端的交互中,他们各自的实现方式。

  1、Remoting的实现。                                                                                          

  在Remoting中,远程对象是一个重要的概念。服务端通过将它注册到制定的信道中,客户端服务端公布的服务端注册的远程对象的URI,通过代理来使用它。在这种架构下的服务端与客户端要实现相互之间的通讯一般是使用事件的方式进行。

  Remoting的通讯模型中分三块,即:1、客户端、2、远程对象、3、寄宿程序(服务端寄宿的应用程序域)。

  注: 远程对象一般通过继承自MarshalByRefObject,而继承自MarshalByRefObject的对象是不会离开它的应用程序域的。并且为了安全,一般我们都是通过将远程对象实现的接口提供给客户端,而不是远程对象。

  一、客户端发送消息到服务端。 客户端获取来远程对象的代理,通过使用它的提供的接口以后,通过信道的传输便到了远程对象。远程对象在收到消息后,用事件的方式通过服务端以执行相应的操作。这时,事件是定义在远程对象中的,客户端进行操作以后,服务端可以直接通过订阅远程对象的事件而获取消息。

  二、服务端发送消息到客户端。 在服务端 ,由于它是远程对象注册的应用程序域,服务端可以直接使用它。同样,服务端发送消息给客户端,也是通过事件来实现的。与客户端主动发送消息给服务端不同的是,定义在远程对象的事件运行在服务端,无法序列化到客户端。这种情况下,一般我们可以通过一种类似"中介者"的方式来进行操作。

  Remoting的程序结构如下图:

                 

  说明:

 Client:为客户端程序。为了可视性,为将他建成一个Winform的项目  CommandAssembly:为公共程序集。它是客户端与服务端共享的一个类库,它包括远程对象实现的接口定义。    Host:为服务端程序,即远程对象寄宿的应用程序。同样它是一个Winform的项目    RemoteObject:为远程对象。

  首先,看看远程对象实现的接口定义:

01 /// <summary>

02 /// 服务端通知客户端时的事件

03 /// </summary>

04 event   DataChangeCallBack DataChangeEventHandler;

05  

06 /// <summary>

07 /// 服务端促触发事件函数

08 /// </summary>

09 /// <param name="entityName"></param>

10 void   ServerSideDataChange( string   entityName);

11  

12 /// <summary>

13 /// 客户端调用服务端使用的接口函数

14 /// </summary>

15 /// <param name="entityName"></param>

16 void   ClientSideDataChange( string   entityName);

   其次:远程对象的定义:

public   class   RemoteObject : MarshalByRefObject, IDataChange

     {

         public   event   DataChangeCallBack DataChangeEventHandler;

 

         public   event   DataChangeCallBack ClientDataChangeEventHandler;

         #region IDataChange 成员

 

         public   void   ServerSideDataChange( string   entityName)

         {

             if   (DataChangeEventHandler ==  null )  return ;

             foreach   (Delegate datachange  in   DataChangeEventHandler.GetInvocationList())

             {

                 DataChangeCallBack temp = datachange  as   DataChangeCallBack;

                 try

                 {                   

                     temp(entityName);

                 }

                 catch

                 {

                     DataChangeEventHandler -= temp;

                 }

             }

         }

 

         public   void   ClientSideDataChange( string   entityName)

         {

             if   (ClientDataChangeEventHandler !=  null )

             {

                 ClientDataChangeEventHandler(entityName);

             }

         }

 

         #endregion

 

         public   override   object   InitializeLifetimeService()

         {

             return   null ;

         }

     }

   注意: 在远程对象的显示中,重写来基类的InitializeLifetimeService函数,目的是为了远程对象永不过期。这涉及到远程对象生命周期的问题。有兴趣的同学可以了解一下(为记忆中,远程对象生存期为6分钟)。如果不重写此函数,在远程对象被GC回收后,如果再有客户端想通过URI获取它的代理将会出错。因为它早已被GC回收了。

  再次,主要看看服务端通知客户端时,使用的"中介者"对象的定义:

public   class   EventWrapper : MarshalByRefObject,IDataChange

     {

 

         public   event   DataChangeCallBack DataChangeEventHandler;

 

         #region IDataChange 成员

 

         public   void   ServerSideDataChange( string   entityName)

         {

             if   (DataChangeEventHandler!= null )

             {

                 DataChangeEventHandler(entityName);

             }

         }

 

         public   void   ClientSideDataChange( string   entityName)

         {

 

         }

         #endregion

     }

   最后就是服务端与客户端信道、事件注册,以及消息的发送问题了。这里主要给出客户端实现(因为涉及服务端事件通知客户端的问题)。服务端类似。

private   void   ClientForm_Load( object   sender, EventArgs e)

      {

          UnregisterChannels();

          RegisterChannel();

          RegisterEvent();

      }

       

 

      void   UnregisterChannels()

      {

          if   (ChannelServices.RegisteredChannels.Length == 0)

          {

              return ;

          }

          foreach   (IChannel channel  in   ChannelServices.RegisteredChannels)

          {

              ChannelServices.UnregisterChannel(channel);

          }

      }

 

      void   RegisterChannel()

      {

          IDictionary hashtable =  new   Hashtable();

          hashtable[ "port" ] = 0;

          BinaryClientFormatterSinkProvider provider =  new   BinaryClientFormatterSinkProvider();

          TcpChannel tcpChannel =  new   TcpChannel(hashtable, provider,  null );

          ChannelServices.RegisterChannel(tcpChannel,  true );

      }

 

      void   RegisterEvent()

      {

          instance = Activator.GetObject( typeof (IDataChange),  " tcp://127.0.0.1:8888/DataService " )  as   IDataChange;

          wrapper =  new   EventWrapper();

          wrapper.DataChangeEventHandler+= new   DataChangeCallBack(wrapper_DataChangeEventHandler);

          instance.DataChangeEventHandler += wrapper.ServerSideDataChange;           

      }

 

      void   wrapper_DataChangeEventHandler( string   entityName)

      {

          if   (txtReceiveMsg.InvokeRequired)

          {

              txtReceiveMsg.Invoke( new   ShowMessageCallBack(wrapper_DataChangeEventHandler), entityName);

          }

          else

          {

              txtReceiveMsg.Text = entityName;

          }

      }

 

      private   void   btnSend_Click( object   sender, EventArgs e)

      {

          if   (! string .IsNullOrEmpty(txtSendMsg.Text))

          {

              instance.ClientSideDataChange(txtSendMsg.Text);

          }

      }

   程序运行界面如下图:

  服务端:

  

  客户端:

 

   注: 在信道的定义中,应该使用与之对应的格式化标识符。

  2、WCF的实现                                                                                                 

  在WCF中,实现服务端与客户端的通讯一般通过双工的模式进行。在WCF中支持双工的绑定协议有:netTcpBinding、wsDualHttpBingding。在WCF实现的服务端与客户端通讯的示例中,为选择来前一种协议。

  程序的结构图如下:


  同样,为了可视化,Host与Client也为Winform程序。

  在WCF的实现中,实现的功能为Remoting完全相同。

  首先看看服务契约定义:

[ServiceContract(CallbackContract= typeof (ICallBack))]

public   interface   IDataChange

{

     [OperationContract(IsOneWay= true )]

     void   Register();

 

     [OperationContract(IsOneWay= true )]

     void   ServerSideDataChange( string   entityName);

 

     [OperationContract(IsOneWay =  true )]

     void   ClientSideDataChange( string   entityName);

}

   回调契约定义:

public   interface   ICallBack

{

     [OperationContract(IsOneWay= true )]

     void   DataChange( string   entityName);

 

}

   服务的实现代码:

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single,ConcurrencyMode=ConcurrencyMode.Single)]

   public   class   DataService : IDataChange

   {

       public   event   DataChangeCallBack ReceiveClientDataChangeHandler;

       ICallBack callBack;

 

       #region IDataChange 成员

 

       public   void   Register()

       {

           callBack = OperationContext.Current.GetCallbackChannel<ICallBack>();

       }

 

       public   void   ServerSideDataChange( string   entityName)

       {

           callBack.DataChange(entityName);

       }

 

       public   void   ClientSideDataChange( string   entityName)

       {

           if   (ReceiveClientDataChangeHandler !=  null )

           {

               ReceiveClientDataChangeHandler(entityName);

           }

       }

 

       #endregion

   }

    服务在Winform中的寄宿代码如下:

private   void   ServerFrom_Shown( object   sender, EventArgs e)

{

     Thread thread =  new   Thread(ServiceStart);

     thread.Start();

}

 

void   ServiceStart()

{

     Uri address =  new   Uri( "net. tcp://127.0.0.1:8806/DataService " );

     using   (ServiceHost host =  new   ServiceHost(service, address))

     {

         host.Open();

         tipStatus.Text =  "服务已经启动" ;

         while   ( true )

         {

             Thread.Sleep(100);

         }

     }

}

  而在客户端,直接通过窗体实现了回调接口,将窗体封装在InstanceContext里,让窗体对象成为服务端回调操作的对象,服务端回调客户端时直接将信息发送给窗体。在客户端窗体的FormLoad事件里做如下定义:

InstanceContext context =  new   InstanceContext( this );

dataChange =  new   ClientProxy(context);

dataChange.Register();

   客户端通知服务端的方式比较简单,也就是主动去调用服务接口。代码如下:

if   (! string .IsNullOrEmpty(txtSendMsg.Text))

      {

          dataChange.ClientSideDataChange(txtSendMsg.Text);

      }

   这样,在客户端调用服务端接口时候,触发服务端事件来通知窗体做数据显示。

  服务通知客户端时通过回调客户端,将消息发送给客户端。代码如下:

Form.cs
if (! string .IsNullOrEmpty(txtSendMsg.Text))
{
service.ServerSideDataChange(txtSendMsg.Text);
}

// DataSerive.cs
public void ServerSideDataChange( string entityName)
{
callBack.DataChange(entityName);
}

  如此这般,便实现了在WCF架构下实现服务端与客户端的通讯。

  运行界面与上面类似。就不重复给出了。

  代码下载地址: https://files.cnblogs.com/tyb1222/Project.rar

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于.Net Remoting与WCF通讯比较的详细内容...

  阅读:35次