|
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.
Rename the source file to UDPChannel to reflect the application that to be developed. |
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.
You can use the following class name if you want.
|
|
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; } } } } |