Listening Client

In this listening client I use the standard Dot Net TcpClient. Speed is not much of an issue here because I normally use this class for cases where I have a client that will send a command request to a server and the server is sending messages to a third party server.

As the responses come back from that third party server, the server then forwards those responses back to the client. So the client is sending a request and as the responses come back the client adds them to a collection (static ConcurrentQueue defined in the Form). Now the form (UI of the client) can display the responses in a ListView or a DataGridView.

So, this client is what I use for sending control messages and receiving responses as the tasks are completed by the server. I use this design for a good reason. Instead of client classes communicating directly with that third party server, it is better to have a running service/daemon to contain that logic.

Why? Because in the industrial systems in which I have developed software it is common to have a situation where a third party server such as an elevator control server only allows one connection and it must be persistent. That means that if you have a running service that executes DB queries and is connected to the third party server, the client cannot connect to that third party server. The running service with the persistent connection is also performing queries to a central database as it forms messages to send to the third party server. Since this client does not have access to that database, this is another reason to do things this way.


using System;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Client
{
    class ListeningClient
    {
        private bool connected;
        private TcpClient socket;
        NetworkStream stream;
        LingerOption option;
        Task threadLstn;
        Task threadSnd;

        public bool connect(string address, int port)
        {
            try
            {
                option = new LingerOption(true, 2);
                socket = new TcpClient { SendTimeout = 2000, ReceiveTimeout = 2000, LingerState = option };
                socket.Connect(address, port);
                start();
                connected = true;

                return connected;
            }
            catch (Exception e)
            {
                MessageBox.Show("Client EXCEPTION 1: " + e.Message);
                return false;
            }
        }

        public void start()
        {
            threadLstn = Task.Factory.StartNew(new Action(listener), TaskCreationOptions.LongRunning);
            stream = socket.GetStream();
        }

        public bool disconnect()
        {
            try
            {
                connected = false;

                stream.Close();
                socket.Client.Shutdown(SocketShutdown.Both);
                socket.Client.Close();
                socket.Close();

                return true;
            }
            catch (Exception e)
            {
                MessageBox.Show("Client EXCEPTION 2: " + e.Message);
                return false;
            }
        }

        public bool send(string message)
        {
            if (connected)
            {
                try
                {
                    byte[] outStream = System.Text.Encoding.ASCII.GetBytes(message);
                    stream.WriteTimeout = 2000;
                    stream.Write(outStream, 0, outStream.Length);
                    stream.Flush();
                }
                catch // if we fail to send the message, let's try to reconnect
                {
                    return false;
                }
                return true;
            }
            return false;
        }

        private void listener() // catch responses as they come back
        {
            string response = "";
            byte[] buffer;

            while (connected)
            {
                while (stream.DataAvailable)
                {
                    buffer = new byte[512];
                    stream.Read(buffer, 0, buffer.Length);
                    response = System.Text.Encoding.ASCII.GetString(buffer);
                    response = response.TrimEnd(' ', '\0');

                    Form1.responses.Enqueue(response); // Your form control (collection) goes here.
                    stream.Flush();                    // In my design, 'responses' is a static ConcurrentQueue collection defined in the Form. 
                }                                      // So the Consumer thread running in that Form accesses this collection to pop, delete 
                                                       // and update the Form Control ListView, DataGridView or whatever you chose to use.
                Thread.Sleep(5);
            }
        }
    }
}