< Implementing Client-Server Remoting Channel | Main | Creating the C# UDP Remoting Channel Class Library (Cont) >


 

 

Chapter 12 Part 7:

.NET Remoting

 

 

What do we have in this chapter 12 Part 7?

  1. UDP Custom Channel C# .NET Remoting Program Example

  2. Creating the UDP Remoting Channel Class Library

 

UDP Custom Channel C# .NET Remoting Program Example

 

In this C# program example we will have two DLL (UDPChannel and DemoUDPChannelCS) files that will be references from the client (ClientUDPChannelCS) and server (ServerUDPChannelCS) programs. We will create the two DLL first and then followed by server and client programs.

 

Creating the UDP Remoting Channel Class Library

 

Create a new C# class library and you may want to use the solution and project names as shown in the following screenshot.

 

Creating the C# UDP Remoting Channel Class Library: creating new class library project

 

Rename the source file to UDPChannel to reflect the application that to be developed.

 

Creating the C# UDP Remoting Channel Class Library: renaming the C# source file

 

Add/edit the code as given below.

 

using System;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Messaging;

using System.Collections;

using System.Threading;

using System.Net;

 

namespace UDPChannelSample

{

    public class UDPChannel : IChannelReceiver, IChannelSender

    {

        private IClientChannelSinkProvider m_ClientSinkProvidersChain = null;

        private UDPServerTransportSink m_ServerTransportSink;

 

        private int m_ChannelPriority = 1;

        private string m_ChannelName = "udp";

        private int m_ChannelPort = 5150; // default port

 

        private Thread m_ServerThread = null;

        private ChannelDataStore m_ChannelDataStore;

 

        // #region <label>...#endregion used for the collapsible code portion

        // for more readable and organized codes

        #region Constructors

 

        // This constructor is used by a client application to

        // programmatically configure the client side of the remoting channel.

        public UDPChannel()

        {

            SetupClientSinkProviders(null);

        }

 

        // This constructor is used by a server application to

        // programmatically configure the server side of the remoting channel.

        public UDPChannel(int Port)

            : this()

        {

            m_ChannelPort = Port;

            SetupServerSinkProviders(null);

        }

 

        // This constructor is used by the .Net remoting infrastructure

        // to configure the channel via a configuration file.

        public UDPChannel(

            IDictionary Properties,

            IClientChannelSinkProvider ClientProviderChain,

            IServerChannelSinkProvider ServerProviderChain

            )

        {

            if (Properties != null)

            {

                foreach (DictionaryEntry Entry in Properties)

                {

                    switch ((string)Entry.Key)

                    {

                        case "name": m_ChannelName = (string)Entry.Value;

                            break;

                        case "priority": m_ChannelPriority = Convert.ToInt32(Entry.Value);

                            break;

                        case "port": m_ChannelPort = Convert.ToInt32(Entry.Value);

                            break;

                    }

                }

            }

 

            SetupClientSinkProviders(ClientProviderChain);

            SetupServerSinkProviders(ServerProviderChain);

        }

 

        #endregion

 

        internal void SetupClientSinkProviders(IClientChannelSinkProvider ClientProviderChain)

        {

            if (ClientProviderChain == null)

            {

                // Install at least default formatter for serialization

                m_ClientSinkProvidersChain = new BinaryClientFormatterSinkProvider();

            }

            else

            {

                // Get the provider chain from the outside

                m_ClientSinkProvidersChain = ClientProviderChain;

            }

 

            // Move to the end of the sink provider chain           

            IClientChannelSinkProvider TempSinkProvider = m_ClientSinkProvidersChain;

 

            while (TempSinkProvider.Next != null)

                TempSinkProvider = TempSinkProvider.Next;

 

            // Append our new UDP channel sink to the end

            TempSinkProvider.Next = new UDPClientChannelSinkProvider();

        }

 

        internal void SetupServerSinkProviders(IServerChannelSinkProvider InputSinkProvider)

        {

            string MachineName = Dns.GetHostName();

 

            m_ChannelDataStore = new ChannelDataStore(null);

            m_ChannelDataStore.ChannelUris = new string[1];

            m_ChannelDataStore.ChannelUris[0] = m_ChannelName + "://" + MachineName +

                ":" + m_ChannelPort.ToString();

 

            IServerChannelSinkProvider ServerSinkProvidersChain;

 

            // Create a default sink provider if one was not passed in

            if (InputSinkProvider == null)

            {

                ServerSinkProvidersChain = new BinaryServerFormatterSinkProvider();

            }

            else

            {

                ServerSinkProvidersChain = InputSinkProvider;

            }

 

            // Collect the rest of the channel data:

            IServerChannelSinkProvider provider = ServerSinkProvidersChain;

            while (provider != null)

            {

                provider.GetChannelData(m_ChannelDataStore);

                provider = provider.Next;

            }

 

            // Create a chain of sink providers

            IServerChannelSink next = ChannelServices.CreateServerChannelSinkChain(ServerSinkProvidersChain, this);

 

            m_ServerTransportSink = new UDPServerTransportSink(next);

 

            StartListening(null);

        }

 

        #region IChannel Members

 

        public string ChannelName

        {

            get

            {

                return m_ChannelName;

            }

        }

 

        public int ChannelPriority

        {

            get

            {

                return m_ChannelPriority;

            }

        }

 

        public string Parse(string Url, out string ObjectUri)

        {

            return ChannelIO.Parse(Url, out ObjectUri);

        }

 

        #endregion

 

        #region IChannelSender Members

 

        public IMessageSink CreateMessageSink(string Url, object RemoteChannelData, out string ObjectUri)

        {

            // Set the out parameters

            ObjectUri = null;

            string ChannelUri = null;

 

            if (Url != null)

            {

                ChannelUri = Parse(Url, out ObjectUri);

            }

            else

            {

                if (RemoteChannelData != null)

                {

                    IChannelDataStore DataStore = RemoteChannelData as IChannelDataStore;

                    if (DataStore != null)

                    {

                        ChannelUri = Parse(DataStore.ChannelUris[0], out ObjectUri);

 

                        if (ChannelUri != null)

                            Url = DataStore.ChannelUris[0];

                    }

                }

            }

 

            if (ChannelUri != null)

            {

                if (Url == null)

                    Url = ChannelUri;

 

                // Return the first sink of the newly formed sink chain

                return (IMessageSink)m_ClientSinkProvidersChain.CreateSink(this, Url, RemoteChannelData);

            }

 

            return null;

        }

 

        #endregion

 

        #region IChannelReceiver Members

 

        public void StartListening(object data)

        {

            m_ServerThread = new Thread(new ThreadStart(this.ServerThreadRoutine));

            m_ServerThread.IsBackground = true;

            m_ServerThread.Start();

        }

 

        public object ChannelData

        {

            get

            {

                return m_ChannelDataStore;

            }

        }

 

        public void StopListening(object data)

        {

            if (m_ServerThread != null)

            {

                m_ServerThread.Abort();

                m_ServerThread = null;

            }

        }

 

        public string[] GetUrlsForUri(string ObjectUri)

        {

            string[ ] UrlArray = new string[1];

 

            if (!ObjectUri.StartsWith("/"))

                ObjectUri = "/" + ObjectUri;

 

            string MachineName = Dns.GetHostName();

 

            UrlArray[0] = m_ChannelName +

                "://" + MachineName + ":" +

                m_ChannelPort + ObjectUri;

 

            return UrlArray;

        }

 

        #endregion

 

        private void ServerThreadRoutine()

        {

            m_ServerTransportSink.RunServer(m_ChannelPort);

        }

    }

}

 

 

 

 

Next, add new class library. Invoke the Add > New Item page.

 

Creating the C# UDP Remoting Channel Class Library: invoking the Add New Item page

 

You can use the following class name if you want.

 

Creating the C# UDP Remoting Channel Class Library: adding new class library to the existing project

 

Add/edit the code as given below.

 

using System;

using System.Text;

using System.Collections;

using System.IO;

using System.Runtime.Remoting.Channels;

using System.Net;

using System.Net.Sockets;

 

namespace UDPChannelSample

{

    public class ChannelIO

    {

        public static string Parse(string Url, out string ObjectUri)

        {

            ObjectUri = null;

            string ChannelUri = null;

 

            try

            {

                System.Uri ParsedURI = new System.Uri(Url);

 

                ChannelUri = ParsedURI.Authority;

                ObjectUri = ParsedURI.AbsolutePath;

            }

            catch (Exception)

            {

                ObjectUri = null;

                ChannelUri = null;

            }

 

            return ChannelUri;

        }

 

        const ushort HeaderMarker = 0xFFA1;

        const ushort HeaderEndMarker = 0xFFA2;

 

        public static void PrepareInboundMessage(byte[ ] Buffer,

            out ITransportHeaders RequestHeaders,

            out Stream RequestStream)

        {

            try

            {

                MemoryStream MS = new MemoryStream(Buffer);

                BinaryReader BR = new BinaryReader(MS);

 

                RequestHeaders = new TransportHeaders();

 

                string Uri = BR.ReadString();

 

                if (Uri != null && Uri != "")

                {

                    string ObjectUri;

                    string ChannelUri = ChannelIO.Parse(Uri, out ObjectUri);

                    if (ChannelUri == null)

                    {

                        ObjectUri = Uri;

                    }

                    RequestHeaders[CommonTransportKeys.RequestUri] = ObjectUri;

                }

 

                // Get the headers

                ushort HM = BR.ReadUInt16();

 

                if (HM != HeaderMarker && HM != HeaderEndMarker)

                {

                    throw new Exception("Invalid message was received");

                }

 

                while (HM != HeaderEndMarker)

                {

                    string HeaderName = BR.ReadString();

                    string HeaderValue = BR.ReadString();

                    RequestHeaders[HeaderName] = HeaderValue;

 

                    // read header marker

                    HM = BR.ReadUInt16();

                }

 

                int StreamSize = BR.ReadInt32();

                // Get the request stream

                RequestStream = new MemoryStream(Buffer, (int)BR.BaseStream.Position, StreamSize);

            }

            catch (Exception e)

            {

                Console.WriteLine("ProcessIncomingMessage failed with error: " + e.Message);

                RequestHeaders = null;

                RequestStream = null;

            }

        }

 

        public static void PrepareOutboundMessage(string Uri,

            ITransportHeaders RequestHeaders,

            Stream RequestStream,

            out byte[ ] Buffer

            )

        {

            try

            {

                // Setup a memory stream to hold the entire message

                MemoryStream MS = new MemoryStream(2048);

                BinaryWriter BW = new BinaryWriter(MS, Encoding.UTF8);

 

 

 

 

                //

                // Write the headers to the memory buffer

                //

                // Format is:

                //

                // URI string

                // <header marker>

                // header name string

                // header value string

                // <header marker>

                // ...

                // <header end marker>

                // <Request stream size>

                // <Request stream bytes>

                //

 

                // Write the URI whatever it is

                BW.Write(Uri);

 

                foreach (DictionaryEntry Header in RequestHeaders)

                {

                    string HeaderName = (string)Header.Key;

 

                    // skip headers beginning with "__"

                    if ((HeaderName.Length < 2) || ((HeaderName[0] != '_') && (HeaderName[1] != '_')))

                    {

                        BW.Write(HeaderMarker);

 

                        BW.Write(HeaderName);

                        BW.Write(Header.Value.ToString());

                    }

                }

 

                BW.Write(HeaderEndMarker);

 

                const int bufsize = 256;

                byte[ ] TransferBuffer = new byte[bufsize];

 

                BW.Write((int)(RequestStream.Length));

 

                int len;

 

                do

                {

                    len = RequestStream.Read(TransferBuffer, 0, bufsize);

                    if (len > 0)

                    {

                        BW.Write(TransferBuffer);

                    }

                }

                while (len != 0);

 

                BW.Flush();

                MS.Position = 0;

                Buffer = MS.ToArray();

            }

            catch (Exception e)

            {

                Console.WriteLine("PrepareOutgoingMessage failed with error: " + e.Message);

                Buffer = null;

            }

        }

    }

}

 


< Implementing Client-Server Remoting Channel | Main | Creating the C# UDP Remoting Channel Class Library (Cont) >