|
Creating the UDP Remoting Channel Class Library (continue)
Next, add a new class. Invoke the Add > New Item page.
You may want to use the following class name if you want.
|
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.
You can use the following class name if you want.
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.
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.
|
|
From the .NET page, browse and select System.Runtime.Remoting. Click OK.
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 >