< UDP Custom Channel C# .NET Remoting Program Example | Main | Completing the C# Custom Remoting Channel Program Example >


 

 

Chapter 12 Part 8:

.NET Remoting

 

 

What do we have in this chapter 12 Part 8?

  1. Creating the UDP Remoting Channel Class Library (continue)

 

Creating the UDP Remoting Channel Class Library (continue)

 

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

 

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

 

You may want to use the following class name if you want.

 

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

 

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.IO;

using System.Net;

using System.Net.Sockets;

 

namespace UDPChannelSample

{

    /// <summary>

    /// Summary description for UDPServerChannel.

    /// </summary>

    internal class UDPServerTransportSink : IServerChannelSink

    {

        private IServerChannelSink m_Next;

        internal UDPServerTransportSink(IServerChannelSink Next)

        {

            m_Next = Next;

        }

 

        #region IServerChannelSink Members

 

        public System.IO.Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, object state, IMessage msg, ITransportHeaders headers)

        {

            return null;

        }

 

        public System.Runtime.Remoting.Channels.ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, System.IO.Stream requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out System.IO.Stream responseStream)

        {

            responseMsg = null;

            responseHeaders = null;

            responseStream = null;

 

            throw new NotSupportedException();

        }

 

        public void AsyncProcessResponse(IServerResponseChannelSinkStack sinkStack, object state, IMessage msg, ITransportHeaders headers, System.IO.Stream stream)

        {

            throw new NotSupportedException();

        }

 

        public IServerChannelSink NextChannelSink

        {

            get

            {

                return m_Next;

            }

        }

 

        #endregion

 

        #region IChannelSinkBase Members

 

        public IDictionary Properties

        {

            get

            {

                return null;

            }

        }

 

        #endregion

 

        public void RunServer(int Port)

        {

            IPEndPoint LocalEP = new IPEndPoint(IPAddress.Any, Port);

            Socket ReceivingSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

 

            ReceivingSocket.Bind(LocalEP);

 

            for (int i = 0; i < 5; i++)

            {

                ServerRequestState State = new ServerRequestState();

 

                State.S = ReceivingSocket;

 

                IPEndPoint RemoteIPEndPoint = new IPEndPoint(IPAddress.Any, 0);

                SocketAddress RemoteAddress = new SocketAddress(AddressFamily.InterNetwork);

                State.RemoteEP = RemoteIPEndPoint.Create(RemoteAddress);

 

                State.S.BeginReceiveFrom(State.RequestBuffer, 0, State.RequestBuffer.Length, SocketFlags.None,

                    ref State.RemoteEP, new AsyncCallback(ServerRequestHandler), State);

            }

            Thread.Sleep(Timeout.Infinite);

        }

 

        private class ServerRequestState

        {

            public byte[ ] RequestBuffer = new byte[65536];

            public Socket S = null;

            public EndPoint RemoteEP = null;

        }

 

        private void ServerRequestHandler(IAsyncResult ar)

        {

            ServerRequestState State = (ServerRequestState)ar.AsyncState;

            State.S.EndReceiveFrom(ar, ref State.RemoteEP);

            ITransportHeaders RequestHeaders;

            Stream RequestStream;

 

            try

            {

                ChannelIO.PrepareInboundMessage(State.RequestBuffer, out RequestHeaders, out RequestStream);

                // Setup a sink stack to pass to Process message in the next sink

                ServerChannelSinkStack SinkStack = new ServerChannelSinkStack();

                SinkStack.Push(this, null);

                // Setup the response to hand back to the client

                IMessage ResponseMessage;

                ITransportHeaders ResponseHeaders;

                Stream ResponseStream;

                // Call the upstream sinks process message

                ServerProcessing Processing = this.NextChannelSink.ProcessMessage(

                    SinkStack,

                    null,

                    RequestHeaders,

                    RequestStream,

                    out ResponseMessage,

                    out ResponseHeaders,

                    out ResponseStream);

 

                // handle response

                switch (Processing)

                {

                    case ServerProcessing.Complete:

                        // Call completed synchronously send the response immediately

                        SinkStack.Pop(this);

                        // Prepare response to send back to client

                        byte[ ] SendBuffer;

                        ChannelIO.PrepareOutboundMessage("", ResponseHeaders, ResponseStream, out SendBuffer);

                        int BytesSent = State.S.SendTo(SendBuffer, State.RemoteEP);

                        break;

 

                    case ServerProcessing.OneWay:

                        break;

 

                    case ServerProcessing.Async:

                        SinkStack.StoreAndDispatch(this, null);

                        break;

                }

            }

            catch (Exception)

            {

                // Problem with inbound message - just ignore and continue.

            }

 

            State.S.BeginReceiveFrom(State.RequestBuffer, 0, State.RequestBuffer.Length, SocketFlags.None,

                ref State.RemoteEP, new AsyncCallback(ServerRequestHandler), State);

        }

    }

}

 

 

 

 

Next, add another class for the client channel definition. Invoke the Add > New Item page.

 

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

 

You can use the following class name if you want.

 

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

 

Add/edit the code as given below.

 

 

 

 

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Messaging;

using System.Collections;

using System.Reflection;

using System.IO;

using System.Net;

using System.Net.Sockets;

 

namespace UDPChannelSample

{

    internal class UDPClientChannelSinkProvider : IClientChannelSinkProvider

    {

        #region IClientChannelSinkProvider Members

 

        public IClientChannelSink CreateSink(IChannelSender channel, string url, object remoteChannelData)

        {

            return new UDPClientTransportSink(url);

        }

 

        public IClientChannelSinkProvider Next

        {

            get

            {

                // In the client, we are at the end of the sink chain in the client so return null.

                return null;

            }

            set

            {

                throw new NotSupportedException();

            }

        }

 

        #endregion

    }

 

    internal class UDPClientTransportSink : IClientChannelSink

    {

        private Socket m_Socket = null;

        private IPEndPoint m_ServerEp = null;

 

        internal UDPClientTransportSink(string url)

        {

            int Port = 5150; // default port

            string Server = null;

 

            System.Uri ParsedURI = new Uri(url);

 

            if (ParsedURI.Port != -1)

            {

                Port = ParsedURI.Port;

            }

 

            Server = ParsedURI.Host;

            IPHostEntry IPHost = Dns.GetHostEntry(Server);

            m_ServerEp = new IPEndPoint(IPHost.AddressList[0], Port);

            m_Socket = new Socket(

                AddressFamily.InterNetwork,

                SocketType.Dgram,

                ProtocolType.Udp

                );

        }

 

        ~UDPClientTransportSink()

        {

            if (m_Socket != null)

            {

                m_Socket.Close();

                m_Socket = null;

            }

        }

 

        #region IClientChannelSink Members

 

        public void AsyncProcessRequest(IClientChannelSinkStack SinkStack,

            IMessage Msg,

            ITransportHeaders RequestHeaders,

            System.IO.Stream RequestStream)

        {

            IMethodCallMessage MCM = (IMethodCallMessage)Msg;

            string Uri = MCM.Uri;

            MethodBase MB = MCM.MethodBase;

 

            byte[ ] RequestBuffer = null;

 

            ChannelIO.PrepareOutboundMessage(Uri,

                RequestHeaders,

                RequestStream,

                out RequestBuffer

                );

 

            // We will create a new client socket to handle a specific asynchronous request.

            Socket S = new Socket(

                AddressFamily.InterNetwork,

                SocketType.Dgram,

                ProtocolType.Udp

                );

 

            // NOTE: UDP is a connectionless protocol that does not ensure the data

            // you send is received by a peer. As a result, to make UDP reliable you

            // have to implement a scheme where a client and server transmits and

            // receives acknowledgements that indicate the peer has received the message.

            // This sample DOES NOT handle making UDP data transmission reliable therefore

            // it is possible that a client may stop communicating with the server because

            // of packet loss in this sample. It is up to the developer to expand the

            // capabilities of this sample to implement reliability over UDP.

            S.SendTo(RequestBuffer, m_ServerEp);

            bool OneWay = RemotingServices.IsOneWay(MB);

 

            if (OneWay)

            {

                S.Close();

            }

            else

            {

                AsyncProcessRequestState State = new AsyncProcessRequestState();

                State.S = S;

                State.SinkStack = SinkStack;

 

                IPEndPoint RemoteIPEndPoint = new IPEndPoint(IPAddress.Any, 0);

                SocketAddress RemoteAddress = new SocketAddress(AddressFamily.InterNetwork);

                EndPoint RemoteEP = RemoteIPEndPoint.Create(RemoteAddress);

 

                S.BeginReceiveFrom(State.ResponseBuffer, 0, State.ResponseBuffer.Length, SocketFlags.None, ref RemoteEP,

                    new AsyncCallback(AsyncProcessRequestHandler), State);

            }

        }

 

        private class AsyncProcessRequestState

        {

            public byte[] ResponseBuffer = new byte[65536];

            public IClientChannelSinkStack SinkStack = null;

            public Socket S = null;

        }

 

        private void AsyncProcessRequestHandler(IAsyncResult ar)

        {

            AsyncProcessRequestState State = (AsyncProcessRequestState)ar.AsyncState;

            EndPoint RemoteEP = null;

 

            if (State.S.EndReceiveFrom(ar, ref RemoteEP) > 0)

            {

                ITransportHeaders ResponseHeaders = null;

                System.IO.Stream ResponseStream = null;

 

                ChannelIO.PrepareInboundMessage(State.ResponseBuffer, out ResponseHeaders, out ResponseStream);

                State.SinkStack.AsyncProcessResponse(ResponseHeaders, ResponseStream);

            }

 

            State.S.Close();

        }

 

        public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack, object state,

            ITransportHeaders headers,

            System.IO.Stream stream)

        {

            // We are last in the chain - no need to implement

            throw new NotSupportedException();

        }

 

        public System.IO.Stream GetRequestStream(IMessage msg, ITransportHeaders headers)

        {

            // We don't do any serialization here.

            return null;

        }

 

        public void ProcessMessage(IMessage Msg,

            ITransportHeaders RequestHeaders,

            System.IO.Stream RequestStream,

            out ITransportHeaders ResponseHeaders,

            out System.IO.Stream ResponseStream)

        {

            IMethodCallMessage MCM = (IMethodCallMessage)Msg;

            string Uri = MCM.Uri;

 

            byte[ ] RequestBuffer = null;

 

            ChannelIO.PrepareOutboundMessage(Uri,

                RequestHeaders,

                RequestStream,

                out RequestBuffer

                );

 

            IPEndPoint RemoteIPEndPoint = new IPEndPoint(IPAddress.Any, 0);

            SocketAddress RemoteAddress = new SocketAddress(AddressFamily.InterNetwork);

            EndPoint RemoteEP = RemoteIPEndPoint.Create(RemoteAddress);

 

            byte[ ] ResponseBuffer = new byte[65536];

 

            // NOTE: UDP is a connectionless protocol that does not ensure the data

            // you send is received by a peer. As a result, to make UDP reliable you

            // have to implement a scheme where a client and server transmits and

            // receives acknowledgements that indicate the peer has received the message.

            // This sample DOES NOT handle making UDP data transmission reliable therefore

            // it is possible that a client may stop communicating with the server because

            // of packet loss in this sample. It is up to the developer to expand the

            // capabilities of this sample to implement reliability over UDP.

            m_Socket.SendTo(RequestBuffer, m_ServerEp);

            int BytesReceived = m_Socket.ReceiveFrom(ResponseBuffer, ref RemoteEP);

            ChannelIO.PrepareInboundMessage(ResponseBuffer, out ResponseHeaders, out ResponseStream);

        }

 

        public IClientChannelSink NextChannelSink

        {

            get

            {

                return null;

            }

        }

 

        #endregion

 

        #region IChannelSinkBase Members

 

        public System.Collections.IDictionary Properties

        {

            get

            {

                return null;

            }

        }

 

        #endregion

    }

}

 

Take note that all the class is using the same namespace. We can bundle all the classes into one source file, however it will be very long. Furthermore, by separating those classes, it should be more organized and readable.

Next, we are ready to build the DLL class library. Build the project.

 

Creating the C# UDP Remoting Channel Class Library: building the project

 

Well, there are errors. Those namespaces actually are from the System.Runtime.Remoting which was included in the using directive. This means we need to do the reference manually.

c:\WINDOWS\Microsoft.NET\Framework\v3.5\Csc.exe /noconfig /nowarn:1701,1702 /errorreport:prompt /warn:4 /define:DEBUG;TRACE /reference:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll" /reference:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Data.DataSetExtensions.dll" /reference:c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Data.dll /reference:c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.dll /reference:c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Xml.dll /reference:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Xml.Linq.dll" /debug+ /debug:full /filealign:512 /optimize- /out:obj\Debug\UDPChannel.dll /target:library ChannelIO.cs UDPChannel.cs Properties\AssemblyInfo.cs UDPClientChannel.cs UDPServerChannel.cs

C:\networkdotnetproject\UDPChannel\UDPChannel\UDPChannel.cs(79,50): error CS0246: The type or namespace name 'BinaryClientFormatterSinkProvider' could not be found (are you missing a using directive or an assembly reference?)

C:\networkdotnetproject\UDPChannel\UDPChannel\UDPChannel.cs(111,48): error CS0246: The type or namespace name 'BinaryServerFormatterSinkProvider' could not be found (are you missing a using directive or an assembly reference?)

C:\networkdotnetproject\UDPChannel\UDPChannel\ChannelIO.cs(58,36): error CS0103: The name 'CommonTransportKeys' does not exist in the current context

 

Compile complete -- 3 errors, 0 warnings

========== Build: 0 succeeded or up-to-date, 1 failed, 0 skipped ==========

Invoke the Add Reference page.

 

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

 

From the .NET page, browse and select System.Runtime.Remoting. Click OK.

 

Creating the C# UDP Remoting Channel Class Library: selecting the System.Runtime.Remoting .NET namespace

 

Rebuild the project and this time there should be no error anymore. A sample build messages are shown below. The DLL was successfully generated.

Compile complete -- 0 errors, 0 warnings

UDPChannel -> C:\networkdotnetproject\UDPChannel\UDPChannel\bin\Debug\UDPChannel.dll

========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

 


< UDP Custom Channel C# .NET Remoting Program Example | Main | Completing the C# Custom Remoting Channel Program Example >