Click here to Skip to main content
15,867,686 members
Articles / Desktop Programming / ATL
Article

TCP Remoting Windows Service Host with Server GC

Rate me:
Please Sign up or sign in to vote.
3.40/5 (3 votes)
14 Apr 2004CPOL4 min read 67.4K   690   20   5
Implement Server GC for TCP Remoting Host.

Introduction

The Server Side published a beta version of "Improving .NET Application Performance and Scalability" by Microsoft Pattern and Practice Group. In chapter 8 about remoting, Windows Service Host for remoting is labeled not optimized since it uses Workstation GC (Garbage Collection). Also according to Gregor Noriskin in this article: "The Server GC is optimized for throughput and multi-processor scalability" and "If you are building a server application that is going to run on multiprocessor machines then it is highly recommended that you use the Server GC".

This article intends to implement a TCP Remoting Host with Server GC. The source code is included for developers in this community to comment and improve. I will try to explain step by step how this host is built, and hopefully generate some interest in writing a truly scalable TCP Remoting Host.

This article primarily targets developers with C# and .NET Framework experience (Remoting). The usage of ATL is at beginner level and is for the sole purpose of creating CLR host.

How to specify Server GC

Server GC has to be specified before AppDomain gets loaded and user code gets executed. So we will have to use unmanaged code. The following is the API from MSDN documentation to do just that:

HRESULT hr = 
CorBindToRuntimeEx(pszVer, pszFlavor, Flags, CLSID_CorRuntimeHost, 
IID_ICorRuntimeHost, (void **)&pHost);

According to this article, pszFlavor = "svr" for CLR Server Build and "wks" for CLR workstation build, and CLR Server build is designed to use multiple processors and is more scalable. As for Flags, STARTUP_CONCURRENT_GC stands for Concurrent GC, and everything else stands for non-concurrent GC. Non-concurrent GC does collection on the same thread as user code, and the server application would be less responsive to a particular request to execute user code, but overall GC Collection performs better. Therefore, for TCP Remoting host that runs as Server Application, I chose to use the API as follows:

LPWSTR pszVer = L"v1.1.4322";
LPWSTR pszFlavor = L"svr";
ICorRuntimeHost *pHost = NULL;  
// this is changed to a global unmanaged variable in download code

HRESULT hr = CorBindToRuntimeEx(pszVer, pszFlavor,  
STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN, CLSID_CorRuntimeHost, 
IID_ICorRuntimeHost, (void **)&pHost);

Clearly, I have defined Server GC as "CLR Server Build with non-concurrent GC" and I believe Server GC has better scalability and can utilize multiple CPU better.

How to get to Default AppDomain:

After creating CLR Host as above, we need to access its default AppDomain to load our Remoting host code. In fact, all managed code must reside in an AppDomain, and Default AppDomain for the CLR Host is the easiest choice:

pHost->Start();
mscorlib::_AppDomain *pDefaultDomain = NULL;
IUnknown   *pAppDomainPunk = NULL;

hr = pHost->GetDefaultDomain(&pAppDomainPunk);
hr = pAppDomainPunk->QueryInterface(__uuidof(mscorlib::_AppDomain), 
                                      (void**) &pDefaultDomain);

Notice that pDefaultDomain is a COM Pointer type from mscorlib.tlb and it allows us to get access to the Default AppDomain from the unmanaged CLR Host. Next, we transit into managed code and load our managed remoting hosting code into this Default AppDomain as follows:

JQD::RemoteObjectLoader *pRemotingHost=NULL;
mscorlib::_ObjectHandle *pObjHandle = NULL;
hr = pDefaultDomain->CreateInstance(_bstr_t("RemoteObjectLoader"), 
                                 _bstr_t("JQD.RemoteObjectLoader"),       
                                  &pObjHandle); 

VARIANT v;
VariantInit(&v);
hr = pObjHandle->Unwrap(&v);
hr =v.pdispVal->QueryInterface(
                     __uuidof(RemoteObjectLoader::_RemoteObjectLoader), 
                    (void**) &pRemotingHost);
pRemotingHost->Load();

Notice that pointer to default AppDomain creates an instance of a managed object with a unmanaged handle, which can be unwrapped and cast into a managed pointer pRemotingHost. This pointer could execute the following C# code:

public class RemoteObjectLoader
  {
   public void Load()
    {
      ChannelServices.RegisterChannel(new TCPChannel(10002));
  RemotingConfiguration.RegisterWellKnownServiceType(
         typeof (JQD.MyClass),
     "MyClassURI", WellKnownObjectMode.SingleCall);
    }
  }

This completes the starting of TCP Remoting using Server GC. As illustrated in the following diagram, this process utilizes both managed and unmanaged code to build the CLR host and eventually load Remoting Hosting code

Diagram for CLR Host

Finally, I have hard coded Remote classes in Load() for illustration. In real world applications, you would use RemotingConfiguration.Configure to expose your objects, and that is what I did in the sample download.

How to run the sample code:

After downloading the zip file, extract it to a directory such as c:\working\CLRMHost. You need to do the following few things:

  • Open the solution (clrmhost.sln) and compile the release build.
  • Copy MyClass.dll from MyClass\Bin\Release to CLRMHost\release.
  • In a Command prompt, change to CLRMHost\Release and type "CLRMHost.exe -i" (this will install the service).
  • If you wish to uninstall the service, run CLRMHost\uninstall.vbs.
  • Open Services MMC and start the service "TCPRemotingHostServerGC".
  • Type http://localhost:10000/MyClassTCPURI?wsdl in IE Browser and you should see WSDL document as a test. You can then write a TCP Remoting client against port 10003 to test TCP Channel.

Some important details

This .NET Solution consists mainly of two projects: a C++.NET Windows Service Project and a Remoting Loader .NET Class Library Project. All unmanaged C++ code resides in the Windows Service Project, which has included important header file mscoree.h for accessing CorBindToRuntimeEx, etc., and atlbase.h for accessing ATL. Furthermore, mscorlib.tlb and RemoteObjectLoader.tlb are imported for transition from unmanaged process to managed code. RemoteObjectLoader.tlb can be generated by command "tlbexp". Note that there is a bug where Config file for Windows Service exe does not get copied to release or debug directory upon compilation. So I have utilized BaseDirectory property for AppDomain to set Remoting Configuration file path instead. Finally, installUtil.exe cannot be used to install this particular Windows Service since that service contains unverifiable C++ unmanaged code. Fortunately, C++ IDE generated code to do installation as "CLRMHost.exe -i". Still to uninstall, you have to run the included VB Script file uninstall.vbs. This script uses WMI to delete the Windows Service "TCPRemotingHostServerGC".

Conclusion

This article provides a reasonably complete implementation for TCP Remoting host using Windows Service and Server GC. Anyone can just download it and add your own object for TCP remoting. Although it does not have proven scalability like IIS hosted HTTP Remoting, overtime developers in this community should be able to get a concrete and real understanding of TCP remoting host, and improving its scalability and throughput.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
I am a Microsoft Certified Application Developer (MCAD), currently focusing on using .Net Framework to develop Business Solutions. I am mostly language neutral. I have used C, C++, ATL, MFC, VB.Net, C#, VB 6, PL/SQL, Transact SQL, ASP, Fortran, etc.

Comments and Discussions

 
GeneralResearch Pin
dvpswe20-May-04 4:47
dvpswe20-May-04 4:47 
GeneralRe: Research Pin
SandeepBassi19-Aug-04 21:52
SandeepBassi19-Aug-04 21:52 
GeneralRe: Research Pin
jqd200123-Aug-04 7:35
jqd200123-Aug-04 7:35 
GeneralRe: Research Pin
KraGiE7-Apr-05 16:51
KraGiE7-Apr-05 16:51 
GeneralRe: Research Pin
jqd200111-Apr-05 4:47
jqd200111-Apr-05 4:47 
Kay,

It would be interesting to see your work on Remoting: VS.Net 2005 has since correctly incorporated Server GC and ADO.Net 2.0 binary Serialization of DataSet. here is Dino's article http://msdn.microsoft.com/msdnmag/issues/04/10/CuttingEdge/[^]

Some performance tests are done at non-professional level since true performnace and scalability test need >$1m lab to begin with --- remoting event /delegate does not work well on network and has some memory issues.

James

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.