Click here to Skip to main content
11,576,060 members (54,341 online)
Click here to Skip to main content

Tagged as

Independent Startup Order of Communicating Applications

, 22 May 2011 CPOL 5K 47 1
Rate this:
Please Sign up or sign in to vote.
A simple example showing how to implement the communication where the client application can start to communicate before the service application is running.

Summary: A simple example showing how to implement the communication where the client application can start to communicate before the service application is running.

Introduction

Typically, the startup order matters in the interprocess communication. It means, the client application assumes that the service application is running and is ready to communicate. This behavior does not have to be a problem for systems, where the service is running most of the time and clients start and stop regularly.
But for systems consisting of more applications running on separate machines and starting approximately at the same time, this behavior causes that somebody (or something) must start the system in a defined order, what complicates life and makes the startup error prone.

The example below implements a simple client-service communication where communicating applications can start independently from each other and the client can start to communicate even before the service is able to receive messages.

The example is based on the Eneter Messaging Framework that provides components for various communication scenarios.
(The framework is free and can be downloaded from http://www.eneter.net. The online help for developers can be found at http://www.eneter.net/OnlineHelp/EneterMessagingFramework/Index.html.)

Buffered Messaging

To implement the independent startup order behavior, we will use Buffered Messaging from the Eneter Messaging Framework.
In case the receiving application is not connected, the Buffered Messaging automatically tries to open the connection and meanwhile stores sent messages into the buffer. Then, when the connection is open, it sends the stored messages to the receiver.

In our independent startup order scenario, if the client starts before the service and sends some message, the message is stored in the buffer. Then, when the service is started and the connection is open, the message from the buffer is sent to the service.

Service Application

The service application is a simple console application communicating via TCP and returning the time. The whole implementation is very simple.

using System;
using Eneter.Messaging.EndPoints.TypedMessages;
using Eneter.Messaging.MessagingSystems.MessagingSystemBase;
using Eneter.Messaging.MessagingSystems.TcpMessagingSystem;

namespace TimeService
{
    class Program
    {
        // The message receiver.
        // It receives 'string' and responses 'DateTime'.
        // Note: the 'string' is not used in this example.
        static IDuplexTypedMessageReceiver<DateTime, string> myReceiver;

        static void Main(string[] args)
        {
            // Create TCP based messaging.
            IMessagingSystemFactory aTcpMessaging = new TcpMessagingSystemFactory();
            IDuplexInputChannel anInputChannel = 
                aTcpMessaging.CreateDuplexInputChannel("tcp://127.0.0.1:7083/");

            // Create typed message receiver.
            IDuplexTypedMessagesFactory aTypedMessagesFactory = 
                new DuplexTypedMessagesFactory();
            myReceiver = aTypedMessagesFactory.CreateDuplexTypedMessageReceiver
            <DateTime, string>();
            myReceiver.MessageReceived += OnMessageReceived;

            // Attach the receiver to the channel and start listening.
            myReceiver.AttachDuplexInputChannel(anInputChannel);

            Console.WriteLine("The service is listening.");
            Console.WriteLine("Press Enter to stop.");
            Console.ReadLine();

            myReceiver.DetachDuplexInputChannel();
        }

        static void OnMessageReceived(object sender, 
        TypedRequestReceivedEventArgs<string> e)
        {
            // Process the incoming request:
            // Just return the current time.
            myReceiver.SendResponseMessage(e.ResponseReceiverId, DateTime.Now);
        }
    }
}

Client Application

The client application is a simple application using the service to retrieve the exact time.
The client application can start and can request the time before the service application is running.
In such a case, the request is stored in the buffer. Then, when the service is ready, the request is delivered and the service responses the time.

Try the following scenario:

  1. Start the client application.
  2. Invoke the request to get the exact time.
  3. Wait few seconds and start the service application.
  4. The client displays the time from the service.

The implementation is very simple.

using System;
using System.Windows.Forms;
using Eneter.Messaging.EndPoints.TypedMessages;
using Eneter.Messaging.MessagingSystems.Composites.BufferedMessagingComposit;
using Eneter.Messaging.MessagingSystems.MessagingSystemBase;
using Eneter.Messaging.MessagingSystems.TcpMessagingSystem;

namespace TimeClient
{
    public partial class Form1 : Form
    {
        // The message sender.
        // It sends 'string' and gets 'DateTime' as the response.
        // Note: the 'string' is not used in this example.
        IDuplexTypedMessageSender<DateTime, string> mySender;

        public Form1()
        {
            InitializeComponent();

            // Create TCP based messaging.
            IMessagingSystemFactory aTcpMessaging = new TcpMessagingSystemFactory();

            // Create the buffered messaging.
            // If the connection is not available, 
            //the buffered messaging tries to reconnect
            // and meanwhile stores sent messages to the buffer.
            // Then, when reconnected, it sends sent messages to the receiver.
            // The following buffered messaging is based on TCP messaging
            // and can work offline 1 minute.
            IMessagingSystemFactory aBufferedMessaging = 
                new BufferedMessagingFactory(aTcpMessaging, TimeSpan.FromMinutes(1));

            IDuplexOutputChannel anOutputChannel = 
                aBufferedMessaging.CreateDuplexOutputChannel("tcp://127.0.0.1:7083/");


            // Create the message sender.
            IDuplexTypedMessagesFactory aTypedMessagesFactory = 
                    new DuplexTypedMessagesFactory();
            mySender = aTypedMessagesFactory.CreateDuplexTypedMessageSender
            <DateTime, string>();
            mySender.ResponseReceived += OnResponseReceived;

            // Attach the output channel and be able to send requests and receive
            // response messages.
            mySender.AttachDuplexOutputChannel(anOutputChannel);
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            // Correctly close the connection.
            mySender.DetachDuplexOutputChannel();
        }

        private void RequestServiceTimeButton_Click(object sender, EventArgs e)
        {
            // Invoke the request to get the current time from the service.
            mySender.SendRequestMessage("not used");
        }

        private void OnResponseReceived(object sender, 
        TypedResponseReceivedEventArgs<DateTime> e)
        {
            if (e.ReceivingError == null)
            {
                // Display the time returned from the service.
                // Note: The response does not come in the UI thread, therefore
                //       it must be transfered to UI thread.
                DateTime aTime = e.ResponseMessage;
                InvokeInUIThread(() => ServiceTimeTextBox.Text = aTime.ToString());
            }
        }

        // Helper method to invoke the given delegate
        // in the UI thread.
        private void InvokeInUIThread(Action action)
        {
            if (InvokeRequired)
            {
                Invoke(action);
            }
            else
            {
                action();
            }
        }
    }
}

And here are communicating applications:

License

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

Share

About the Author

Ondrej_Uzovic
Architect
Slovakia Slovakia
My programming path started in 1987 when I got my first computer Sharp MZ-800.
It came with 8 bit CPU Z80, 64Kb RAM and the tape recorder. It was a great machine. I think I still have it somewhere.
I was fascinated and I started to write first programs. Eventually I became developer and software architect. I like innovations and clean nice solutions.

You may also be interested in...

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150603.1 | Last Updated 22 May 2011
Article Copyright 2011 by Ondrej_Uzovic
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid