Chapter 15. Remoting

.NET Remoting is the functional equivalent of the Java Remote Method Invocation (RMI) framework. Both systems allow applications to communicate between processes and machines, enabling objects in one application to manipulate objects in another. RMI was added to Java after the original release of the platform, while the remoting system in .NET has clearly been factored into the platform design from the start. The deep integration into the .NET Framework makes the remoting system easier to use than RMI. Some key differences are:

  • Remoting doesn’t rely on a registry to locate instances of remote classes. Services must be well known, implying that the client must know the location of the remote service at run time.

  • Remoting doesn’t require remote operations to be handled via interfaces.

  • Remoting doesn’t require stub classes to be compiled. The support for handling remote operations is intrinsic to the CLR.

First Steps

The best way of demonstrating remoting is by example. In this section, we’ll build a simple remote service that adds a series of integer values to a running total. The client sends the server an array of integers and receives back a state object that contains the running total. There is little purpose in such contrived functionality, but the simplicity of this remote service will allow us to illustrate the features of the remoting system.

All of the code files that we’ll create in the following sections should be saved in a single directory.

For these examples, the references for the application must include the System.Runtime.Remoting namespace included in the System.Runtime.Remoting.dll assembly. For more information about compiling with assemblies, see Chapter 3.

Creating the Server

First we define a server class to sum the array of integers sent from the client, accumulating a running total. The class is listed here and should be saved to a file named CountServer.cs.

using System;

public class CountServer : MarshalByRefObject {
    private CountState o_state;

    public CountServer() {
        o_state = new CountState();
    }

    public CountState SumNumbers(params int[] p_values) {
        foreach (int x_value in p_values) {
            o_state.AddNumber(x_value);
        }
        return o_state;
    }

    public CountState State {
        get {
            return o_state;
        }
    }
}

The parts of this class that relate to remoting are marked in boldface. We indicate that the class can be made available remotely by deriving the class from System.MarshalByRefObject. MarshalByRefObject is discussed in the Copies and References section later in this chapter.

We keep track of the running total with the CountState class. CountState provides methods to add new values to the total, clear the total, and return the current total. We have annotated CountState with the Serializable attribute, meaning that it will be passed by value across the network. For general information about this attribute, consult Chapter 10; see the Copies and References section in this chapter for details of the impact on remoting. The CountState class should be saved to a file named CountState.cs in the same directory as the CountServer.cs file.

using System;

[Serializable]
public class CountState {
    private int o_total;

    public void AddNumber(int p_value) {
        o_total += p_value;
    }

    public void Clear() {
        o_total = 0;
    }

    public int GetTotal() {
        return o_total;
    }
}

The CountState and CountServer classes define the functionality for the remoting example, but we still need to define the remoting service. We have created the Start class, shown here, which makes the CountServer type available to remote clients. This class should be saved to a file named Start.cs in the same directory as the previous two files.

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

class Start {

    static void Main(string[] p_args) {

        // create and register the channel
        HttpChannel x_channel = new HttpChannel(20172);
        ChannelServices.RegisterChannel(x_channel);

        // register the count server for remoting
        RemotingConfiguration.RegisterWellKnownServiceType(
            typeof(CountServer), "CountServer",
            WellKnownObjectMode.Singleton);

        Console.WriteLine("Press return to exit.");
        Console.ReadLine();
    }
}

This example introduces the concept of channels. Channels are the means by which clients are able to access the remote service. By using the HttpChannel class and setting the constructor argument to 20172, we’re stating that the service will accept client requests via the HTTP protocol on port 20172. We then register the new channel with the ChannelServices class to activate the network settings and make the channels available for use. Channels are discussed in detail in the Channels section later in this chapter.

After creating the channels, we need to register the CountServer type; until the type is registered, the remoting system won’t accept client requests. This is known as publishing and is achieved with the RegisterWellKnownService-Type method of the RemotingConfiguration class. For the details of publishing objects, see the section entitled Publishing and Activation later in this chapter.

Creating the Client

Now that the server side of the remote service is complete, the next step is to build a client. The client will obtain a remote reference to the server and send over an array of integers to be added, returning the total. The result from the SumNumbers method is an instance of CountState. Finally the GetTotal method is called to print the total.

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

class CountClient {

    CountClient() {
        // create and register the remoting channel
        HttpChannel x_channel = new HttpChannel();
        ChannelServices.RegisterChannel(x_channel);

        // local member to initialize the remoting system
        InitRemoteServer();

        DoRemoteSummation(new CountServer());
    }

    private void InitRemoteServer() {
        RemotingConfiguration.RegisterWellKnownClientType(
            typeof(CountServer),
            "http://localhost:20172/CountServer");
    }

    private void DoRemoteSummation(CountServer p_server) {
        // send some numbers to be added to the total
        CountState x_state = p_server.SumNumbers(1, 2, 3, 4, 5);

        // print out the total
        Console.WriteLine("Sum: {0}", x_state.GetTotal());
    }

    static void Main(string[] args) {
        new CountClient();
    }
}

Remoting clients also need to create a channel. We create and register a client channel using the same approach as in the Start class of the server. We must create the same type of channel for the client as was created for the server, in this case an HttpChannel. However, if no port number is specified, a random port is used.

We have isolated in the InitRemoteServer method the code responsible for defining the relationship with the server, thus allowing us to demonstrate changes later in the chapter without having to detail the entire class each time. The statement in the InitRemoteServer method tells the CLR that when the client instantiates new CountServer instances, the remoting service should be used. The details of this are explained in the Publishing and Activation section later in this chapter. For now we’ll focus on the URL passed as the second argument to the RegisterWellKnownClientType method. This URL defines the location where the remoting system can find the server; in the example, we specify http://localhost:20172/CountServer. Table 15-1 lists the URL elements.

Table 15-1. The URL Elements

Element

Derivation

http://

Specifies that an HTTP channel should be used to connect to the server. The channel created and registered in the CountClient constructor will be used. See the Channels section in this chapter for more details.

localhost:20172/

The port number must match the one defined by the constructor argument used by the server class when instantiating the HttpChannel instance. See the Channels section in this chapter for more details.

CountServer

This is the service name specified by the server in the call to Register-WellKnownServiceType. See the Publishing and Activation section later in this chapter for more information.

After the call to InitRemoteServer, the CountClient calls the SumNumber method to request that the server add the values of an array of integers to the running total, which returns an instance of CountState. The client then prints the value of the CountState.GetTotal method.

Building and Testing the Example

Now that we have created the four C# source files that the example comprises, we can use the C# compiler (csc.exe) to build the executable client and server applications. The first step is to compile the CountServer.cs and CountState.cs files into a DLL/library that can be used by both the client and the server. The following statement shows how this is done using csc.exe:

csc /target:library CountServer.cs CountState.cs

The compiler creates a file named CountServer.dll that we will use in the following steps when creating the client and server executables. The following statement illustrates how to compile the Start.cs file, including the CountServer.dll library:

csc Start.cs /reference:CountServer.dll

The compiler will create a file named Start.exe, which is the server-side executable for our example. The final compilation step creates the client and creates a file named CountClient.exe:

csc CountClient.cs /reference:CountServer.dll

The server is started by typing Start.exe from a command prompt; the client is started by typing CountClient.exe The server must be instantiated before the client can be run. Each time the client is executed, the server total will be incremented. Here’s the output from the client for two separate executions:

Sum: 15
Sum: 30

We have now created a simple distributed application using remoting. The following sections will move on to the detail of how remoting works and the options available to the programmer.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset