Sunday, May 30, 2010

programs on remoting

Remoting


11.1 Introduction

Object running in one Virtual Machine (VM) should be able to access (call functions

on) objects that are in a different Virtual Machine. Usually this means the two

processes are running on two different computers. To set up remoting we proceed

as follows:

Instantiate target object (on server)

Setup our channels

Register our object (on server)

Get a reference to object (on client)

Call method on server from the client

For example on the Server side:

public class Server {

public static void Main() {

Target t = new Target();

RemotingServices.Marshal(t,"me");

IChannel c = new HttpChannel(8080);

ChannelServices.RegisterChannel(c);

Console.WriteLine("Server ready. ");

Console.ReadLine();

}

}

147

148 CHAPTER 11. REMOTING

On the Client side we have

public class Client {

public static void Main() {

string url = "http://localhost:8080/me";

Type to = typeof(Target);

Target t = (Target) RemotingServices.Connect(to,url);

Console.WriteLine("Connected to server.");

try {

string msg = Console.ReadLine();

t.sendMessage(msg);

} catch(Exception e) {

Console.WriteLine("Error " + e.Message);

}

}

}

A shared class (i.e. it is on the Client and Server side) is

public class Target : System.MarshalByRefObject

{

public void sendMessage(string msg)

{ System.Console.WriteLine(msg); }

}

Reference types passed via remoting must be serializable or marshal-by-reference.

Serializable == pass-by-value

Copy of object is made.

MarshalByRefObject == pass-by-reference

proxy object is passed.

An example for the second case is:

public class Counter : MarshalByRefObject {

int count = 0;

public void incCount() { count++; }

public int getCount() { return count; }

}

An example for the first case is:

11.1. INTRODUCTION 149

[Serializable]

public class Counter {

int count = 0;

public void incCount() { count++; }

public int getCount() { return count; }

}

We have to import:

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http; // for Http

using System.Runtime.Remoting.Channels.Tcp; // for Tcp

Shared objects must be available to both the client and the server. Make a separate

assembly for it

csc /t:library Shared.cs

csc /r:Shared.dll Server.cs

csc /r:Shared.dll Client.cs

There are three main items in the process of remoting. The Interface, the Client

and the Server. The Interface is a .dll file (generated from a .cs file) which is on

the Client and Server side. The Server provides an implementation of the Interface

and makes it available to call. The Client calls the Server using the Interface.

150 CHAPTER 11. REMOTING

Example. The client provides a string to the server and the server returns the

length of the string.

We first create an interface with the file MyInterface.cs.

// MyInterface.cs

public interface MyInterface

{

int FunctionOne(string str);

}

MyInterface.cs is on the Server and Client side. We compile to MyInterface.dll

on the Client and Server side with

csc /t:library MyInterface.cs

On the Server side we now create our class which we invoke from a remote machine

(client). RemoteObject.cs is on the Server side and is the implementation of

MyInterface.cs.

// RemoteObject.cs

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

public class MyRemoteClass : MarshalByRefObject, MyInterface

{

public int FunctionOne(string str)

{

return str.Length; // length of string

}

}

Any class derived from MarshalByRefObject allows remote clients to invoke its

methods. Now on the Server side we compile

csc /t:library /r:MyInterface.dll RemoteObject.cs

This creates the file RemoteObject.dll on the Server side.

11.1. INTRODUCTION 151

Next we provide our Server on the Server side.

// ServerTcp.cs

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

public class MyServer

{

public static void Main()

{

TcpChannel m_TcpChan = new TcpChannel(9999);

ChannelServices.RegisterChannel(m_TcpChan,false);

RemotingConfiguration.RegisterWellKnownServiceType(

Type.GetType("MyRemoteClass,RemoteObject"),

"FirstRemote",WellKnownObjectMode.SingleCall);

System.Console.WriteLine("Press ENTER to quit");

System.Console.ReadLine();

} // end Main

} // end class MyServer

First we create a TcpChannel object which we use to transport messages across our

remoting boundary. We select 9999 as the TCP port to listen on. This could cause

problems with firewalls. We use

ChannelServices.RegisterChannel

to register our TcpChannel with the channel services. Then we use

RemoteConfiguration.RegisterWellKnownServiceType

to register our RemoteClass object as a well-known type. Now this object can be

remoted.

We are using the string FirstRemote here which will be used as part of the URL

that the client uses to access the remote object. We use SingleCall mode here

which means a new instance is created for each remote call.

Remark. One could have also used Singleton in which case one object would have

been instantiated and used by all connecting clients.

Next we generate the exe file for ServerTcp via

csc /r:RemoteObject.dll ServerTcp.cs

152 CHAPTER 11. REMOTING

Now we write our Client program ClientTcp.cs on the client side.

// ClientTcp.cs

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

public class MyClient

{

public static void Main()

{

TcpChannel m_TcpChan = new TcpChannel();

ChannelServices.RegisterChannel(m_TcpChan,false);

MyInterface m_RemoteObject =

(MyInterface) Activator.GetObject(typeof(MyInterface),

"tcp://192.168.0.3:9999/FirstRemote");

Console.WriteLine(m_RemoteObject.FunctionOne("willi hans steeb"));

// for LocalHost

// "tcp://LocalHost:9999/FirstRemote");

} // end Main

} // end class MyClient

Just as in the Server we have a TcpChannel object, though in this case we do not

have to specify a port. We also use

ChannelService.RegisterChannel

to register the channel. We use

Activator.GetObject

to obtain an instance of the MyInterface object. The IP address of the remote

machine (Server) is 192.168.0.3 with the port 9999. The string FirstRemote

which forms part of the URL was that we passed to

RemotingConfiguration.RegisterWellKnownServiceType

on the Server.

To obtain the ClientTcp.exe file we run

csc /r:MyInterface.dll ClientTcp.cs

11.1. INTRODUCTION 153

To run everything on the Server side we enter the exe file at the command line

ServerTcp

Then on the Client side we enter the exe file at the command line

ClientTcp

Then we are provide with the length of the string. In the present case 16.

154 CHAPTER 11. REMOTING

Instead of using Tcp we can also use Http. Then the files ServerTcp.cs and

ClientTcp.cs are replaced by ServerHttp.cs and ClientHttp.cs shown below.

// ServerHttp.cs

// on Server side

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

public class MyServer

{

public static void Main()

{

HttpChannel chan = new HttpChannel(8080);

ChannelServices.RegisterChannel(chan,false);

RemotingConfiguration.RegisterWellKnownServiceType(

Type.GetType("MyRemoteClass,RemoteObject"),

"FirstRemote",WellKnownObjectMode.SingleCall);

System.Console.WriteLine("Press ENTER to quit");

System.Console.ReadLine();

} // end Main

} // end class MyServer

11.1. INTRODUCTION 155

// Client.cs

// on client side

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

public class MyClient

{

public static void Main()

{

HttpChannel chan = new HttpChannel();

ChannelServices.RegisterChannel(chan,false);

MyInterface m_RemoteObject =

(MyInterface) Activator.GetObject(typeof(MyInterface),

"http://152.106.41.42:8080/FirstRemote");

Console.WriteLine(m_RemoteObject.FunctionOne("willi hans"));

// for LocalHost

// "tcp://LocalHost:9999/FirstRemote");

} // end Main

} // end class MyClient

No comments:

Post a Comment