| ||||||||||||||||||||||||||||
|
|
|
||||||||||||||||||||||||||||||||||||||||
|
Figure 1 - Naming Service, Servers, and Clients in the Linux ACE/TAO C++ Domain and the Windows XP IIOP.NET C# Domain. A Naming Service can exist in either domains. This article will demonstrate the three examples shown. IntroductionIn theory, there will be some programmers who are fortunate enough to work entirely within the .NET environment and who are able to use the excellent .NET Remoting framework to accomplish all of their distributed computing tasks. In practice, however, the reality is that most programmers are required to work occasionally with collections of legacy code that predates the .NET frameworks (and sometimes predates the .NET programmers!), or current code that - for one reason or another - continues to be produced in alternate languages or frameworks. Inevitably, it seems that real-life programmers will find that they need to have a way to exchange data with non .NET clients and servers across heterogeneous networks and languages. Clearly, this is a huge and complex topic, and many excellent articles and tutorials have already been written on the subject. However, one specific area that seems to me to have been neglected - at least, it seemed that way when I was looking for guidance myself - is a tutorial on how to provide interoperability between ACE/TAO Servers and Clients written in C++ and often running on Linux, and .NET Servers and Clients written in C# and almost always running on Windows. This article will demonstrate the coding techniques that I have been able to use to successfully achieve cross-platform (Windows XP, Linux FC4), cross-language (C#, C++) client-server communication using the "ACE ORB" (TAO) and IIOP.NET. This tutorial consists of three examples:
BackgroundIf you are reading this tutorial, chances are that you are already familiar with either ACE/TAO or .NET, but perhaps not with both. Feel free to skip the parts that you already know. .NET Remoting comes, out of the box, with binary and SOAP channels for the TCP and HTTP protocols. However, to satisfy the requirement to communicate with the Common Object Request Broker Architecture (CORBA), a channel for the IIOP protocol was developed by Dominic Ullmann and Patrik Reali. Their project, which is known as IIOP.NET, provides compatibility with a number of Object Request Brokers (ORBs), including TAO. So far, the major emphasis of the IIOP.NET project has been to support the IIOP protocol between Java and .NET. However, IIOP.NET can also support interoperability with C++ clients and servers through TAO, as this tutorial will show. What You Need to Have Installed to Compile and Run the ExamplesThis tutorial will demonstrate a set of relatively simple examples using some relatively complex software. There are some pieces of software that you must have properly installed before the example code will compile and work for you:
ACE/TAOThe ACE ORB (TAO) is an open source implementation of CORBA. It is based on the standard Object Management Group (OMG) CORBA reference model, and is constructed using software concepts and frameworks provided by the Adaptive Communications Environment (ACE). It is a middleware technology that automates common network programming tasks including:
The implementation languages for ACE/TAO are C and C++. The process that is used to produce servers and clients in ACE/TAO is beyond the scope of this tutorial, but a few concepts are worth reviewing:
IIOP.NETIIOP.NET is an open source (LGPL) project that leverages the .NET Remoting framework by providing a custom channel that supports the IIOP protocol, enabling nearly transparent and seamless communication between distributed CORBA objects. An objective of IIOP.NET was to allow existing CORBA servers to be used without modification, and this objective has been achieved for TAO. Not only will IIOP.NET allow you to use legacy TAO servers without modifying them, but it will also allow you to transparently replace legacy or unmanaged C++ TAO Servers and Clients with managed C# equivalents. Naturally, the implementation language for IIOP.NET is C#. IIOP.NET provides an The Naming ServiceThe trickiest part of getting the client-server communication to work properly in TAO/CORBA systems is dealing with the issues associated with navigating the naming graph - a hierarchy of naming contexts and name bindings. To succeed in this, we need to know something about the OMG Naming Service. The OMG Naming Service is a lot like the Internet Domain Name Service (DNS), and both of these "Name Services" are a lot like the familiar White Pages telephone directory:
The process of "mapping to" is what is meant by name binding. Every name maps to exactly one reference, but the same reference can be mapped to many names - although it is usually a good practice to avoid doing this since it doesn't provide any real value-addition and can cause unnecessary confusion. When you need an object to hold name bindings, you use a naming context, which in .NET terms is conceptually like a namespace, even though it is implemented more like a table. And, like namespaces (or file systems), naming contexts can be nested. The resulting tree of naming context branches and name binding leaves is the name graph. Managing entries and access to the name graph is the job of the Naming Service. TAO Servers register themselves - and their object references - with the TAO Naming Service by binding contexts and objects below the top-level naming context, which is usually called "NameService". TAO clients locate references to the objects that they want to use by first connecting to the NameService naming context, and then working their way down the hierarchy of name-bound naming contexts until they come to the name-bound object they are looking for. Clearly, this scheme will only work when both the server and the client agree about where in the name graph the desired object can be found. The TAO distribution comes with a utility, nslist.exe, that can be used to inspect the name graph of a given Naming Service. A variation of this utility, nslister.exe, is included with the code downloads for this article. (It provides output that is more consistent with the examples, and uses terminology that is more familiar to .NET programmers.) An example of the output from the nslister utility is the following:
Figure 2 - Example output of the nslister.exe
utility showing that something - we don't really know exactly what - is
bound to the "ExampleInterfaces" naming context and the "IAdder" name.
(We can only hope that it really is an object that actually implements
the In .NET Remoting, servers and clients connect directly with each other, and a Naming Service is not required. (Don't confuse the .NET services provided by the combination of the Universal Description, Discovery, and Integration (UDDI), the Discovery Protocol (DISCO), and the Web Service Description Language (WSDL) for a Naming Service - they are entirely different technologies for achieving somewhat the same result, and .NET Remoting does not actually depend upon any of them.) There are three practical consequences that arise from this discussion of Naming Services:
The C# Interface, the IDL File, and the Implementations of BothThe C# Interface and ImplementationFor these examples, we are going to define a very simple example interface, /// IAdder.cs
/// ...
using System;
namespace SLB.ExampleInterfaces
{
/// <summary>The IAdder interface accepts two doubles
/// and returns a double.</summary>
public interface IAdder
{
double add(double arg1, double arg2);
}
}
The interface implementation that will be "served" by the server is written in the same language and for the same platform as the server itself. For the IIOP.NET server - and since it is a very simple interface - it is convenient to put the implementation code into the same file as the server itself. In general, for more complex projects, the implementations should be in their own source files, and combined into a library which the server code will reference. In any event, our implementation looks like this: namespace SLB.ExampleServers
{
/// <summary>
/// The adder implementation class.
/// </summary>
public class Adder: MarshalByRefObject, IAdder
{
public override object InitializeLifetimeService()
{
// live forever
return null;
}
public double add(double arg1, double arg2)
{
return arg1 + arg2;
}
}
Since it is a remotable object, it needs to be derived from the The C++ Interface and ImplementationFor the C++ programs, we need to express this same example interface in an OMG Interface Definition Language (.idl) file, which we will call ExampleInterfaces.idl. #pragma prefix "SLB" module ExampleInterfaces { // The adder interface interface IAdder { double add(in double arg1, in double arg2); }; }; This .idl file can then be used to generate the necessary stubs and skeletons for the TAO implementation using the command: tao_idl -GI ExampleInterfaces.idl. The following files are generated:
For the most part, these generated files contain an indecipherable complexity of code not meant for mortal programmers, and it is best to simply avert one's gaze and give thanks for the courageous coders who have gone before us, selflessly enduring the horrors associated with making such a brutal thing "just work" on our behalf. One of the first things that we should do with these files is to rename the I.cpp and I.h files so that they do not get overwritten if tao_idl is ever again run against the same target .idl file. The convention is to rename them to _i.cpp and _i.h, and one ought to follow this convention because some of the useful downstream utilities (such as the Make Project Creator and Make Workspace Creator) expect it. The one file that we do need to modify (in addition to changing references to the I.h header file here and there as necessary) is the interface implementation file ExampleInterfaces_i.cpp.
Insert the implementation code for the constructors and methods as
necessary, in the places indicated in the generated code. Our
implementation of the CORBA::Double ExampleInterfaces_IAdder_i::add (
::CORBA::Double arg1,
::CORBA::Double arg2
)
ACE_THROW_SPEC ((
CORBA::SystemException
))
{
// Insert the Implementation Here
return (arg1 + arg2); // The implementation.
}
Using the IDLToCLSCompiler and the CLSToIDLGeneratorThe In these cases, the solution to programmer fatigue and tedious errors is to use the purpose-built tools that IIOP.NET provides! If you have written or been given an .idl file, and you need an equivalent .NET .dll to reference in your C# code, then you can use the IDLToCLSCompiler utility to produce the dynamic library automatically. For example, to generate the ExampleInterfaces.dll file from the ExampleInterfaces.idl file, use the following command: IDLToCLSCompiler.exe ExampleInterfaces ExampleInterfaces.idl
On the other hand, if you already have a .NET library that you want to produce an .idl file from, then you can use the CLSToIDLGenerator utility. For example: CLSToIDLGenerator.exe SLB.ExampleInterfaces.IAdder ExampleInterfaces.dll
will automatically produce the following .idl file: // auto-generated IDL file by CLS to IDL mapper // SLB\ExampleInterfaces\IAdder.idl #include "orb.idl" #include "Predef.idl" #include "Ch\Elca\Iiop\GenericUserException.idl" #ifndef __SLB_ExampleInterfaces_IAdder__ #define __SLB_ExampleInterfaces_IAdder__ module SLB { module ExampleInterfaces { abstract interface IAdder { double add(in double arg1, in double arg2) raises (::Ch::Elca::Iiop::GenericUserException); }; #pragma ID IAdder "IDL:SLB/ExampleInterfaces/IAdder:1.0" }; }; #endif The similarities of this file with the manually produced .idl above are obvious, but the differences (which initially look a little alarming) ultimately don't matter. These are powerful utilities; read the documentation, and don't be afraid to use them. Example 1 - IIOP.NET Server and Client on Windows, TAO Client on LinuxThe C# IIOP.NET Server and the C# IIOP.NET ClientThis example uses an IIOP.NET server, written in C# to run on Windows. Here is some of the relevant code: /// DotNetAdderServer.cs
/// ...
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Threading;
// ..\IIOPChannel.dll
using Ch.Elca.Iiop;
// from project ExampleInterfaces.dll
using SLB.ExampleInterfaces;
namespace SLB.ExampleServers
{
/// <summary>
/// This .Net Server class object publishes
/// an SLB.ExampleInterfaces.IAdder implementation
/// using the iiop protocol.
/// </summary>
public class DotNetAdderServer
{
private static string host = "localhost"; //default host
private static int port = 12345; //default port
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
public static void Main(string[] args)
{
try
{
ParseCommandLineArguments(args);
// register the channel
IiopChannel chan = new IiopChannel(port);
ChannelServices.RegisterChannel(chan);
Adder adder = new Adder();
// the adder object is used,
// but only the IAdder interface is seen...
string objectURI = "IAdder";
RemotingServices.Marshal(adder, objectURI);
Console.WriteLine(".Net IAdder Server is Running...");
//" + host + ":" + port.ToString() + "/" + objectURI);
Console.WriteLine("Clients can connect using iiop:
Thread.Sleep(Timeout.Infinite);
}
catch (Exception e)
{
///...
}
}
///...
}
}
}
As you can see, the server code is exactly what you would expect it
to be for .NET Remoting, except that instead of creating and
registering a Similarly, the .NET client is exactly what you would expect, except that it also uses the /// DotNetAdderClient.cs
///...
using System;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting;
// ..\IIOPChannel.dll
using Ch.Elca.Iiop;
using Ch.Elca.Iiop.Services;
// from project ExampleInterfaces.dll
using SLB.ExampleInterfaces;
namespace SLB.ExampleClients
{
/// <summary>
/// This client accepts two numbers from
/// the user at the console, and then
/// calls a remote object that exposes
/// the IAdder interface in order to add them and
/// return the result.
///
/// Usage is: DotNetAdderClient.exe host port
/// </summary>
public class DotNetAdderClient
{
private static string host = "localhost"; //default host
private static int port = 12345; //default port
/// <summary>
/// The entry point for the application.
/// </summary>
/// <param name="args">Command line arguments: host port</param>
[STAThread]
public static void Main(string[] args)
{
try
{
ParseCommandLineArguments(args);
// Register the Channel...
//assign port automatically
IiopClientChannel channel = new IiopClientChannel();
ChannelServices.RegisterChannel(channel);
// Get the reference to the servant object
// using the interface...
IAdder adder =
(IAdder)RemotingServices.Connect(typeof(IAdder),
"iiop://" + host + ":" + port.ToString() +
"/IAdder");
// Use the servant...
InteractWithUser(adder);
}
catch (Exception e)
{
///...
}
}
///...
}
}
The C++ TAO Client for the IIOP.NET ServerThe C++ TAO client bypasses the naming service to connect directly to the IIOP.NET Server. In keeping with TAO/CORBA conventions, the client is started with a command line argument that identifies it - ORBInitRef. In this case, the command line arguments are: -ORBInitRef IAdder=iiop://localhost:12345/IAdder. Some of the relevant TAO client code is presented below: // DirectTAOAdderClient.cpp // // This example demonstrates a direct connection // between a C# .NET IIOPNet based server and a C++ // TAO based client, communicating using // the iiop protocol, and not using a NameService. // ... #include "ExampleInterfacesC.h" #include <acestreams.h><ace/streams.h> int main( int argc, char *argv[] ) { try { // Initialize the CORBA Object Request Broker. CORBA::ORB_var orb = CORBA::ORB_init( argc, argv ); // Instead of using the TAO NameService, // resolve the desired interface directly, based // upon the -ORBInitRef passed in on the // command line and used to initialize the ORB. // For example: -ORBInitRef IAdder=iiop://localhost:12345/IAdder CORBA::Object_var obj = orb->resolve_initial_references("IAdder"); // Narrow to the interface of interest, // and make sure it is the type we expect it to be. ExampleInterfaces::IAdder_var iAdder = ExampleInterfaces::IAdder::_narrow(obj.in()); if (CORBA::is_nil(iAdder.in())) { cerr << "Could not narrow to an IAdder reference" << endl; return 1; } // Now use the remote object... cout << "Using a remote object that " "implements the IAdder interface..." << endl; cout << endl; double number1 = 0; double number2 = 0; double sum = 0; while (true) { cout << "Enter the first number: "; cin >> number1; cout << "Enter the second number: "; cin >> number2; // the remote object is used here... sum = iAdder->add(number1, number2); cout << "The sum is: " << sum << endl; cout << "------------------" << endl; } } catch ( CORBA::Exception& ex ) { cerr << "Caught a CORBA::Exception: " << ex << endl; return 1; } return 0; } You can run this example (all on Windows) using the Example1.bat file provided with the binaries download. To run this example manually, do the following:
Example 2 - TAO Server, TAO Client, TAO Naming Service on Linux, IIOP.NET Client on WindowsThe C++ ACE/TAO Linux Server and ClientFor this example, we will use a TAO Server and TAO Client, both written in C++ and running on Linux. The server code looks like this (note the comments in the code): // TAOAdderServer.cpp // // This is a simple NameService using server implementation using ACE/TAO. // // This example serves an SLB.ExampleInterfaces.IAdder object. // The IAdder object is defined // in ExampleInterfaces.idl and implemented in ExampleInterfaces_i.cpp. //... #include "ExampleInterfaces_i.h" #include <orbsvcs/CosNamingC.h> #include <orbsvcs/Naming/Naming_Client.h> #include <ace/streams.h> int main( int argc, char *argv[] ) { try { // Initialize the CORBA Object Request Broker. CORBA::ORB_var orb = CORBA::ORB_init( argc, argv ); //Get reference to the Root POA CORBA::Object_var obj = orb->resolve_initial_references( "RootPOA" ); PortableServer::POA_var poa = PortableServer::POA::_narrow( obj.in() ); // Activate the POA Manager PortableServer::POAManager_var mgr = poa->the_POAManager(); mgr->activate(); // Find the CORBA Services Naming Service CORBA::Object_var naming_obj = orb->resolve_initial_references("NameService"); CosNaming::NamingContext_var root = CosNaming::NamingContext::_narrow(naming_obj.in()); if(CORBA::is_nil(root.in())) { cerr << "Could not narrow NameService to NamingContext!" << endl; throw 0; } // Bind the Naming Context to a well known // name so clients can find it by name. // Interested parties can see the "well known" // namespace's and interfaces that might // be available on a given NameService using // a utility like nslist or nslister. // It makes sense to use the IDL-defined Module // (namespace) for the first entry... CosNaming::Name name; name.length(1); name[0].id = CORBA::string_dup("ExampleInterfaces"); // Namespace "SLB.ExampleInterfaces" try { CORBA::Object_var dummy = root->resolve(name); } catch (CosNaming::NamingContext::NotFound& ) { // If the binding for that name does not // already exist on NameService, then create it... CosNaming::NamingContext_var dummy = root->bind_new_context(name); } // ... and to use the IDL-defined Interface // (interface or class) for the second entry. name.length(2); name[1].id = CORBA::string_dup( "IAdder" ); // (interface) class "IAdder" // Create a Servant (of the implementation class), // and bind the servant object type to the name. ExampleInterfaces_IAdder_i adderServant; PortableServer::ObjectId_var oid = poa->activate_object(&adderServant); CORBA::Object_var adderServant_obj = poa->id_to_reference(oid.in()); root->rebind(name,adderServant_obj.in()); cout << "IAdder interface has been" " registered on the Naming Service" << endl; // Accept requests orb->run(); orb->destroy(); } catch(CORBA::Exception& ex) { cerr << "Caught a CORBA exception: " << ex << endl; return 1; } return 0; } The C++ Linux TAO client that uses this server is the following (again, note the comments in the code): // TAOAdderClient.cpp //... #include "ExampleInterfacesC.h" #include <orbsvcs/CosNamingC.h> #include <orbsvcs/Naming/Naming_Client.h> #include <ace/streams.h> int main( int argc, char *argv[] ) { try { // Initialize the CORBA Object Request Broker CORBA::ORB_var orb = CORBA::ORB_init( argc, argv ); // Find the CORBA Services Naming Service CORBA::Object_var naming_obj = orb->resolve_initial_references("NameService"); CosNaming::NamingContext_var root = CosNaming::NamingContext::_narrow(naming_obj.in()); if(CORBA::is_nil(root.in())) { cerr << "Could not narrow NameService to NamingContext!" << endl; throw 0; } // Resolve the desired object (ExampleInterfaces.IAdder). // The module and interface bindings // need to be the same here in the client as they // are in the server. CosNaming::Name name; name.length(2); name[0].id = CORBA::string_dup( "ExampleInterfaces" ); // IDL-defined Module (namespace) name[1].id = CORBA::string_dup( "IAdder" ); // IDL-defined Interface (interface class) CORBA::Object_var obj = root->resolve(name); // Narrow to confirm that we have the interface we want. ExampleInterfaces::IAdder_var iAdder = ExampleInterfaces::IAdder::_narrow(obj.in()); if (CORBA::is_nil(iAdder.in())) { cerr << "Could not narrow to an iAdder reference" << endl; return 1; } // Now use the remote object... cout << "Using a remote object that implements" " the IAdder interface..." << endl; cout << endl; double number1 = 0; double number2 = 0; double sum = 0; while (true) { cout << "Enter the first number: "; cin >> number1; cout << "Enter the second number: "; cin >> number2; sum = iAdder->add(number1, number2); cout << "The sum is: " << sum << endl; cout << "------------------" << endl; } } catch ( CORBA::Exception& ex ) { cerr << "Caught a CORBA::Exception: " << ex << endl; return 1; } return 0; } The Windows C# Client for the Linux ACE/TAO ServerAnd finally, here is the most important program of this example. This client, written in C# and running in Windows, will communicate through the TAO Naming Service with the ACE/TAO server running on Linux (or Windows). With a knowledge of the interface (obtained from the .idl) and the information about the name graph (obtained using the nslist.exe or nslister.exe utilities), a programmer should be able to modify this program to communicate with legacy C++ ACE/TAO servers (or IIOP.NET servers that use the Naming Service, as we will see in Example 3). Here is the important code: /// DotNetNSAdderClient.cs
/// ...
using System;
using System.IO;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
// from IIOPChannel.dll
using Ch.Elca.Iiop;
using Ch.Elca.Iiop.Services;
using omg.org.CosNaming;
// from ExampleInterfaces.dll
using SLB.ExampleInterfaces;
namespace SLB.ExampleClients
{
/// <summary>
/// A simple NameService using client that connects
/// to an ACE/TAO server through a TAO NameService.
/// This client consumes a remote SLB.ExampleInterfaces.IAdder interface.
/// </summary>
class DotNetNSAdderClient
{
// private static string host = "localhost";
// FAILS - must use a named or ip-address host.
private static string host = "slb002";
// named host
private static int port = 2809;
// OMG default port for iiop
/// ...
[STAThread]
static void Main(string[] args)
{
try
{
// Process the command line...
ParseArgs(args);
// Register the channel...
IiopClientChannel channel = new IiopClientChannel();
ChannelServices.RegisterChannel(channel);
// Access the COS naming service (NameService)...
CorbaInit init = CorbaInit.GetInit();
NamingContext nameService = init.GetNameService(host, port);
// Access the IDL-defined module
// (which maps to a .Net namespace)...
NameComponent[] moduleName = new NameComponent[]
{new NameComponent("ExampleInterfaces", "")};
NamingContext nameSpace =
(NamingContext)nameService.resolve(moduleName);
// Access the IDL-defined interface
// (which maps to a .NET interface class)
NameComponent[] interfaceName = new NameComponent[]
{new NameComponent("IAdder", "")};
SLB.ExampleInterfaces.IAdder servant =
(SLB.ExampleInterfaces.IAdder)nameSpace.resolve(interfaceName);
// Use the servant...
InteractWithUser(servant);
}
catch (Exception e)
{
/// ...
}
}
/// ...
}
///...
}
There are a few tricky bits:
This example can be run (all on Windows) using the Example2.bat file provided in the binary download. To run this example manually, do the following:
Example 3 - TAO Client and TAO Naming Service on Linux, IIOP.NET Server and IIOP.NET Client on WindowsThis example will reuse the C++ TAO-based Client, the TAO Naming Service, and the IIOP.NET-based Client from Example 2, and will transparently substitute a new IIOP.NET-based Naming Service-using Server. The important code for this server is the following: /// DotNetNSAdderServer.cs
///...
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Threading;
// from ..\IIOPChannel.dll
using Ch.Elca.Iiop;
using Ch.Elca.Iiop.Services;
using omg.org.CosNaming;
// from project ExampleInterfaces.dll
using SLB.ExampleInterfaces;
namespace SLB.ExampleServers
{
/// <summary>
/// The adder implementation class.
/// </summary>
public class Adder: MarshalByRefObject, IAdder
{
///... (See Implementation Above)
}
/// <summary>
/// This .Net Server class object publishes
/// an SLB.ExampleInterfaces.IAdder implementation
/// and registers it on a TAO Naming Service
/// using the iiop protocol.
/// </summary>
public class DotNetAdderServer
{
//FAILS - seems to be associated with
//connecting to running Naming Service...
// private static string host = "localhost";
//use default named or IP host
private static string host = "slb001";
//default port
private static int port = 12345;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
public static void Main(string[] args)
{
try
{
ParseCommandLineArguments(args);
// register the channel
// assign port automatically
IiopChannel chan = new IiopChannel(0);
ChannelServices.RegisterChannel(chan);
// Access the COS naming service (NameService)...
CorbaInit init = CorbaInit.GetInit();
NamingContext nameService =
init.GetNameService(host, port);
// Bind the IDL-defined module
// (which maps to a .Net namespace)...
NameComponent[] moduleName =
new NameComponent[]
{new NameComponent("ExampleInterfaces", "")};
NamingContext nameSpace =
nameService.bind_new_context(moduleName);
// Bind the IDL-defined interface
// (which maps to a .NET interface class)
NameComponent[] interfaceName =
new NameComponent[]
{new NameComponent("IAdder", "")};
Adder interfaceImplimentation = new Adder();
nameSpace.bind(interfaceName,interfaceImplimentation);
Console.WriteLine(".Net IAdder Server is Running...");
Console.WriteLine("Clients can connect using" +
" the TAO NamingService on Host:" +
host + " Port:" + port.ToString());
Thread.Sleep(Timeout.Infinite);
}
catch (Exception e)
{
///...
}
}
///...
}
}
Again, since we are connecting to a Naming Service we need to use a
named or IP host. Also, note how it is necessary to navigate the name
graph using the This example can be run (all on Windows) using the Example3.bat file provided in the binary download. To run this example manually, do the following:
ConclusionsIn this tutorial, you have seen how an ACE/TAO client written in C++, and running on Windows or Linux, can communicate directly with a .NET server, using the IIOP protocol. In addition, you have seen a technique that will let you write C# .NET clients, using IIOP.NET, that can communicate with legacy C++ ACE/TAO servers, running on Windows or Linux. Finally, you have also seen how you can write a C# IIOP.NET server that will use a Naming Service, and that can transparently replace an existing C++ ACE/TAO server. The practical value of these techniques, using the excellent IIOP.NET package, should begin to be realized by .NET programmers who have until now been required to interoperate with legacy ACE/TAO code, and thought that the only way to do this effectively was to abandon the .NET framework and the C# language for the native C and C++ language and legacy frameworks of ACE/TAO. What I hope that these examples demonstrate is that continuing to use C++ - or deciding to use C# and .NET - to work with an ACE/TAO legacy is now an actual choice that a programmer can make. About Stephen Bogner
| ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||
General comment
News / Info
Question
Answer
Joke / Game
Admin message
|
All Topics, C#, .NET >> C# Programming >> Remoting
Updated: 30 Nov 2005 16:14 |
Article content copyright Stephen Bogner, 2005 everything else Copyright © CodeProject, 1999-2005. Advertise on The Code Project | Privacy |
| The Ultimate Toolbox • MSDN Communities | ASP Alliance • Developer Fusion • Developersdex • DevGuru • Programmers Heaven • Planet Source Code • Tek-Tips Forums • |