2014年5月8日 星期四

簡易IPCChannel 實作

Inter Process communication 指的是同一台電腦底下不同Process之間的溝通機制,
參考wiki-IPC可以發現,實現的方式有非常多種。
而在不同的程式語言基礎下,
各家提供的實作方式也都不太一樣。
Windows C#提供了一個蠻簡易的類別可以使用,
叫做IPCChannel,
沒錯!!就是這麼的直覺= = ,
其實他是直接組合了將兩個類別,
IpcClientChannel 和 IpcServerChannel 組合在一起。
參考MSDN: IPCChannel
以下是將程式碼簡化到最簡~
做出最簡易的程式碼。



首先是必備的遠端操控物件 RemoteObject
//務必繼承MarshalByRefObject
class RemoteObject : MarshalByRefObject
 {
  private int callCount = 0;
   
  //提供遠端呼叫操控使用的Method
  public int GetCount()
  {
   //這段程式碼會印在Server上
   Console.WriteLine( "GetCount has been called." );
   callCount++;
   //回傳結果至Client
   return ( callCount );
  }

 }

接著是IPCCommunicator

public class IPCCommunicator
 {
  private const String _serverChannel = "localhost:9090";
  private const String _remoteObjUri = "RemoteObject.rem";
  public void Server()
  {
   CreatIPCServerBy( _serverChannel );

   // Wait for the user prompt.
   Console.WriteLine( "Press ENTER to exit the server." );
   Console.ReadLine();
   Console.WriteLine( "The server is exiting." );
       }

  private void CreatIPCServerBy(String channelName)
  {
   // 新增一個IPCChannel Instance用來裝載IPC連線的相關資訊。
   // Create the server channel.
   IpcChannel serverChannel = new IpcChannel( channelName );

   // 將該Instance註冊為Server。
   // Register the server channel.
   ChannelServices.RegisterChannel( serverChannel );

   // 必須要註冊一個用來遠端操控的物件型別,Type就是RemoteObject 。
   // _remoteObjUri代表Uri的位置,加上原本Server的portName組成了Url=ipc://localhost:9090/RemoteObject.rem
   // 代表供外界操控連結的指定位置。
   // 採用Singleton代表所有聯繫同一個Url的操作物件都是操作同一個實體。
   // Expose an object for remote calls.
   RemotingConfiguration.RegisterWellKnownServiceType( typeof( RemoteObject ), _remoteObjUri, WellKnownObjectMode.Singleton );
  }

  public void Client()
  {
   //取得IPC Server的操控物件
   var service = GetRemoteObjBy( "ipc://" + _serverChannel + "/" + _remoteObjUri );
   Console.WriteLine( "The client is invoking the remote object." );
   Console.WriteLine( "The remote object has been called {0} times.", service.GetCount() );

  }


  private RemoteObject GetRemoteObjBy( String ObjUrl )
  {
   // 藉由Url取得已知操作物件。
   // Register as client for remote object.
   WellKnownClientTypeEntry remoteType = new WellKnownClientTypeEntry( typeof( RemoteObject ), ObjUrl );
   // 註冊該型別,使得所有Instance都能指向遠端操作的物件
   RemotingConfiguration.RegisterWellKnownClientType( remoteType );

   //回傳新的Instance,此時操作的就是Server上面的物件。
   return new RemoteObject();
  }
 }

以下為主程式:
class Program
 {
  static void Main( string[] args )
  {
   var ipcCommuncator = new IPCCommunicator();
_Retry:
   Console.WriteLine("Plz Choice Ur Want to ");
   switch (Console.ReadLine())
   {

    case "Server":
     ipcCommuncator.Server();
     Console.WriteLine( "type any key to Stop Server" );
     Console.Read();
     break;
    case "Client":
     ipcCommuncator.Client();
     Console.WriteLine( "type any key to Stop Client" );
     Console.Read();
     break;
    default:
     goto _Retry;
   }
  }
 }