|
The C# Column
Remoting Basics - II
In
the previous article we had built the remotable class and the server application.
Let us now build the client application.
The client also needs to register the remotable class and create and register
the channel. The client has been created as a Console Application
and named UserClient. The code in UserClient is given below.
using System ;
using System.Runtime.Remoting ;
using System.Runtime.Remoting.Channels ;
using System.Runtime.Remoting.Channels.Tcp ;
using UserLib ;
namespace UserClient
{
class Class1
{
static void Main ( string[ ] args )
{
string url = tcp://localhost:500/User ;
RemotingConfiguration.
RegisterWellKnownClientType
( typeof ( User ), url ) ;
TcpClientChannel channel =
new TcpClientChannel( ) ;
ChannelServices.RegisterChannel (
channel ) ;
User u = new User( ) ;
Console.WriteLine ( u.getuser( ) ) ;
}
}
}
Here we have registered the remotable class using the RegisterWellKnownClientType(
) method. This method registers the remotable class that is registered with
RegisterWellKnownServiceType( ). To the RegisterWellKnownClientType( ) method
we have passed the type of the User class and the URI where the remote class
is located.
The protocol mentioned in the URI (tcp in this case) must match the protocol
of the channels registered. The machine name should be the one where the server
is running. You can replace localhost with any other machine name or an IP address
if you plan to execute the server on some other machine. The port number following
the machine name must match the port number specified in the server. Finally,
the object URI that follows the port number must also match the object URI that
we specified in the server.
After registering the remotable class, we have created and registered the channel.
Since we used a TCP channel in the server it is necessary to use the same type
of channel here. So we created an instance of the TcpClientChannel type. Then
we registered the channel using the RegisterChannel( ) method.
Next we created
an instance of the User class and called the getuser( ) method of the User class.
We added the reference of UserLib.dll to get information about the User class.
To test this application, we must first execute the server. On doing so we would
get the Press Enter to terminate message. Next we need to start
the client. On doing so the name of the user currently logged on the machine
would get displayed in the clients console window. If we run the server
and client on different machines with different user names, the client would
display the user name of the server. While running the programs on different
machines do not forget to change the machine name in UserClient application.
A question might come to your mindin view of the fact that UserLib.dll
is referenced in UserClient, is the client creating a local object using the
UserLib.dll? The answer is no. To check this out, try the following.
If we execute the client without starting the server, we get a System.Net.Socket.SocketExecption
exception. On the other hand if we execute the server on another machine but
comment out all the registration logic from the client and run the client, the
client displays the name of the user logged on to the client machine and not
the name of the user logged on to the server machine. This is because in this
case it does create a local object using the referenced UserLib.dll.
Server Activated Objects and Client Activated Objects
Now let us discuss the methods used to register a remotable class in the server
as well as the client. There are two methods available through which we can
register a remotable class in the serverRegisterActivatedServiceType(
) and RegisterWellKnownServiceType( ). On similar lines we also have two methods
to register a remotable class in the clientRegisterActivatedClientType(
) and RegisterWellKnownClientType( ).
These methods are actually used to specify the type of the remotable object.
There are two types of remotable objectsserveractivated objects
and clientactivated objects.
Serveractivated objects are registered using RegisterWellKnownServiceType(
) in the server application and RegisterWellKnownClientType( ) in the client
application. This is what we have used in our UserServer and UserClient projects.
Clientactivated objects are registered with RegisterActivatedServiceType(
) in server application and RegisterActivatedClientType( ) in the client application.
The following table shows the overview of the above discussion.
Serveractivated objects are so called because when the client calls new(
) to create an instance of the remote class, only a proxy gets created in the
client. The object does not get created or activated. The object gets created
only when a method call is placed through the proxy. So, the server actually
decides when the object should get created.
Clientactivated objects, on the other hand, are created on the server
the moment the client calls new( ). Thus here the client decides when the object
should get created.
Another difference between the two is that clientactivated objects can
be activated using nonzeroargument constructors but serveractivated
objects cannot. This is because for serveractivated objects, the calls
to new( ) dont map with the actual creation of the object. On the other
hand clientactivated objects can be instantiated with any constructor
as both the proxy and the object are created at the same time.
Whenever we register a serveractivated object, we specify a mode. The
two supported activation modes used for serveractivated objects are WellKnownObjectMode.SingleCall
and WellKnownObjectMode.Singleton. WellKnownObjectMode is an enumeration and
SingleCall and Singleton are the members of this enumeration. Recall that we
used SingleCall as the activation mode in UserServer.
The difference between the two activation modes is that if we specify SingleCall
to be the activation mode, a new instance of User would get created for each
and every method call placed by any client. As against this, if we specify Singleton
as the activation mode only one instance of User would be created and it would
process all method calls from all clients.
SingleCall activation mode is said to offer a one-shot service. If there is
one client and it places ten method calls on the remote object, ten remotable
objects and one proxy would get created. If there are ten clients, each placing
ten method calls on the remotable object, a hundred remotable objects and ten
proxies would get created.
This is because on every method call a new object would get created. The objects
created do not maintain any state between method calls as well as between clients.
On the other hand, if we specify the activation mode to be Singleton, a single
object gets created regardless of how many calls are being placed by how many
clients. If there is one client and it places ten method calls then only one
remotable object and only one proxy would get created.
Suppose there are ten clients and ten method calls are placed. Even in this
case just one remotable object but ten proxies for ten clients would get created.
Since the same object is shared we can understand why a Singleton object maintains
state between method calls as well as between different clients.
A word of caution! While working with Singleton objects we need to be aware
of thread safety. What we have here is a single object shared between clients.
If two clients make calls on the same object at the same time then we must ensure
that the calls are thread safe.
Clientactivated objects lie midway between serveractivated
Singleton objects and serveractivated SingleCall objects. This is because,
every call to new( ) by a client creates a new clientactivated object.
The objects created are not shared between clients and they serve only that
client which created them. Which out of the several models available for activation
of the remote object to use totally depends on the design of the application.
 |
Yashavant Kanetkar, one of the first
Express Computer columnists, is an established software expert, speaker
and author with several best-sellers to his credit, including titles like
“Let Us C” and the “Fundas” series. Contact him at kanetkar@dcubesoft.com |
|