Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / WCF

Sending Messages to Workstations using Socket Programming and WCF

4.75/5 (5 votes)
4 Apr 2011CPOL3 min read 20K  
How to send messages to workstations

I am in the process of developing an application which sends information to client machines from another application (some sort of an Internal Messaging System or Desktop Alerts). Initially, I had thought of using the old school NETSEND command but there are issues with it, and the main hindrance for me not using it is that it is not in the newer versions of Windows and you cannot really control how it looks and feels so I ended up developing my own.

Image 1

There are a lot of options before I started like Message Queuing, Remoting and others but I ended up with two methods of delivering my message. This post will show you the basics on how to do it in those two methods.

Socket Programming

First, we go to Socket Programming. With this method, you will be requiring a lot of work and testing as this is the most Raw as you can get. Having said that this will be a lot faster as you develop things that you only need, so using this method, you will have to create your own protocol, serialization (if you need), security features, etc.

Now for our sample, we need only 2 components - the Receiver and Sender. We will be developing it using Windows forms and here is how it goes.

Receiver Form - This will be responsible for receiving messages from the sender, so this should always run in the background and listens in full-time so any messages sent are received instantaneously.

C#
using System;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
namespace Receiver
{
    public partial class Form1 : Form
    {
        public AsyncCallback oWorkerCallBack;
        public Socket oSocketListener;
        public Socket oSocketWorker;
        public int ListeningPort = 8000;

        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            Listen();
        }
        private void Listen()
        {
            try
            {
                //Declare Socket Listener
                oSocketListener = new Socket(AddressFamily.InterNetwork, 
                    SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint oLocalIP = new IPEndPoint(IPAddress.Any, ListeningPort);

                //Local IP Address Binding
                oSocketListener.Bind(oLocalIP);

                //Start Listening
                oSocketListener.Listen(10);

                //Create Callback for Client Connections
                oSocketListener.BeginAccept(new AsyncCallback(OnConnect), null);
                lblApplicationMessage.Text = "Listening on Port : " + ListeningPort;
            }
            catch (SocketException ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        public void OnConnect(IAsyncResult oAsyncResult)
        {
            try
            {
                oSocketWorker = oSocketListener.EndAccept(oAsyncResult);
                WaitForData(oSocketWorker);
            }
            catch (ObjectDisposedException)
            {
                System.Diagnostics.Debugger.Log(0, "1", 
                    "\n OnConnect: Socket has been closed\n");
            }
            catch (SocketException ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        public void WaitForData(System.Net.Sockets.Socket oSocket)
        {
            try
            {
                if (oWorkerCallBack == null)
                    oWorkerCallBack = new AsyncCallback(OnReceive);

                SocketPacket oSocketPacket = new SocketPacket();
                oSocketPacket.oSocket = oSocket;

                // Start Listening for any Data
                oSocket.BeginReceive(oSocketPacket.bDataBuffer, 0, 
                    oSocketPacket.bDataBuffer.Length, SocketFlags.None, oWorkerCallBack,
                    oSocketPacket);
            }
            catch (SocketException ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        public void OnReceive(IAsyncResult oAsyncResult)
        {
            try
            {
                SocketPacket oSocketID = (SocketPacket)oAsyncResult.AsyncState;

                //Stop Receive
                int iRecieve = 0;
                iRecieve = oSocketID.oSocket.EndReceive(oAsyncResult);

                //Build the message
                char[] chars = new char[iRecieve + 1];
                System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
                int iCharLen = d.GetChars(oSocketID.bDataBuffer, 0, iRecieve, chars, 0);
                string sData = new string(chars);
                txtMessageRecieved.Text = txtMessageRecieved.Text + sData;

                //Wait again
                WaitForData(oSocketWorker);
            }
            catch (ObjectDisposedException)
            {
                System.Diagnostics.Debugger.Log(0, "1",
                    "\n OnReceive: Socket has been closed\n");
            }
            catch (SocketException ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        public class SocketPacket
        {
            public System.Net.Sockets.Socket oSocket;
            public byte[] bDataBuffer = new byte[1];
        }
    }
}

Sender Form – This will be the one sending the messages to the receiver to this is only used when needed.

C#
using System;
using System.Windows.Forms;
using System.Net.Sockets;

namespace Sender
{
    public partial class Form1 : Form
    {
        Socket oSocket = null;
        public string sRecieverIP = "10.10.10.10";
        public int iRecieverPort = 8000;
        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            Connect();
        }
        private void btnSend_Click(object sender, EventArgs e)
        {
            try
            {
                Object oData = txtMessage.Text;
                byte[] bData = System.Text.Encoding.ASCII.GetBytes(oData.ToString());
                oSocket.Send(bData);
            }
            catch (SocketException se)
            {
                MessageBox.Show(se.Message);
            }
        }
        private Socket Connect()
        {
            try
            {
                //Creating a Client Socket
                oSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
                    ProtocolType.Tcp);

                System.Net.IPAddress oIPAddress = System.Net.IPAddress.Parse(sRecieverIP);
                System.Net.IPEndPoint oEndPoint = new System.Net.IPEndPoint(oIPAddress,
                    iRecieverPort);
                oSocket.Connect(oEndPoint);

                return oSocket;
            }
            catch (SocketException se)
            {
                MessageBox.Show(se.Message);
                return null;
            }
        }
        private void Disconnect(Socket oSocket)
        {
            //Close socket on both sender and receiver
            oSocket.Shutdown(SocketShutdown.Both);
            oSocket.Close();
        }
    }
}

WCF or Windows Communication Foundation

Now let’s go to WCF or Windows Communication Foundation, it is an application programming interface in the .NET Framework for building connected, service-oriented applications like the one we want to achieve. We also need to know that the base of WCF is also Socket programming that’s why if you use this approach, most of the work is done for you and you will see how easy it is to implement from the codes below. With WCF, you get plumbing, serialization, protocols, security features, etc. and all you need is to choose
the features you need and configure. Now with that overhead, this will be slower than the first method.

We will be creating the same 2 forms in this method but we need an additional one to implement a service and we also need an Application configuration to define the endpoint configuration.

WCF Main Receiver Form – This is used for service implementation, I used Windows Form for ease of use in debugging but you can implement it as a service, console or any way you want the invoke the receiver form.

C#
using System;
using System.Windows.Forms;
using System.ServiceModel;
using System.ServiceProcess;
namespace WCFReceiver
{
    public partial class Form1 : Form
    {
        public ServiceHost oServiceHost = null;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            if (oServiceHost != null)
            {
                oServiceHost.Close();
            }
            // Create a ServiceHost for the Service type and provide the base address.
            oServiceHost = new ServiceHost(typeof(NotificationService));

            // Open the ServiceHostBase to create listeners and start listening for messages.
            oServiceHost.Open();
        }

    }

    // Define a Service Contract.
    [ServiceContract(Namespace = "http://WCFReceiver")]
    public interface INotifyClient
    {
        [OperationContract]
        bool SetPopUp(string sMessage);
    }

    // Implement the Service Contract in a Service Class.
    public class NotificationService : INotifyClient
    {
        public bool SetPopUp(string sMessage)
        {
            try
            {
                FormMsgReciever oPopup = new FormMsgReciever(sMessage);
                oPopup.Show();
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}

Pop Up Form - This is the receiver form to show the messages coming from the sender.

C#
using System;
using System.Windows.Forms;

namespace WCFReceiver
{
    public partial class FormMsgReciever : Form
    {
        private string sRecievedMessage;
        public FormMsgReciever(string sMessage)
        {
            InitializeComponent();
            sRecievedMessage = sMessage;
        }

        private void FormMsgReciever_Load(object sender, EventArgs e)
        {
            txtMessageRecieved.Text = sRecievedMessage;
        }
    }
}

Application Config - This is the configuration file to define endpoints

XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <!-- This section is optional 
      with the new configuration model introduced in .NET Framework 4. -->
      <service name="WCFReceiver.NotificationService" 
      behaviorConfiguration="NotificationServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8005/Notifier/service"/>
          </baseAddresses>
        </host>
        <endpoint address="" binding="wsHttpBinding" 
        contract="WCFReceiver.INotifyClient" />
        <endpoint address="mex" binding="mexHttpBinding" 
        contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="NotificationServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="False"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

Once you have all of the 3 items above ready, build it then execute it so you can set a reference for the service reference your sender application.

Make sure you run it as an administrator.

Image 2

Otherwise, you will encounter this message “HTTP could not register URL http://+:portnumber/Directory/. Your process does not have access rights to this namespace“.

Image 3

Once all OK, add it as a reference to your Sender project.

Image 4

WCF Sender – This will be the form used in sending the messages.

C#
using System;
using System.Windows.Forms;

namespace WCFSender
{
    public partial class Form1 : Form
    {
        public string sRecieverIP = "10.10.10.10";
        public int iRecieverPort = 8000;
        public string sEndpointConfigName = "WSHttpBinding_INotifyClient";

        public Form1()
        {
            InitializeComponent();
        }
        private void btnSend_Click(object sender, EventArgs e)
        {
            string sServiceAddress = "http://" + sRecieverIP + ":" + 8000 + 
                "/Notifier/service";

            ServiceReference1.NotifyClientClient oNotify = 
                new ServiceReference1.NotifyClientClient(sEndpointConfigName, sServiceAddress);

            bool bSuccess = oNotify.SetPopUp(txtMessage.Text);
            if (!bSuccess)
            {
                MessageBox.Show("Error in sending message");
            }
            Application.Exit();
        }
    }
}

Now for my choice of method, it’s all up to you what suits best as I had given the pros and cons of each method, you just have to weigh which best works in your situation.

License

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