Click here to Skip to main content
15,888,162 members
Home / Discussions / C#
   

C#

 
AnswerRe: Load specific userControl from DLL Pin
Bernhard Hiller29-May-15 5:55
Bernhard Hiller29-May-15 5:55 
Generalvideo streaming mvc3 c#,html5 and jquery Pin
saiguttina29-May-15 0:25
saiguttina29-May-15 0:25 
GeneralMessage Closed Pin
28-May-15 23:39
Member 1172789928-May-15 23:39 
AnswerRe: help with calculator program Pin
V.28-May-15 23:45
professionalV.28-May-15 23:45 
AnswerRe: help with calculator program Pin
OriginalGriff29-May-15 0:08
mveOriginalGriff29-May-15 0:08 
QuestionSharePoint Pin
Armugam Indrani28-May-15 22:41
professionalArmugam Indrani28-May-15 22:41 
AnswerRe: SharePoint Pin
Eddy Vluggen29-May-15 2:50
professionalEddy Vluggen29-May-15 2:50 
QuestionTCP Heartbeat background Thread Pin
MooKowMyke27-May-15 21:50
MooKowMyke27-May-15 21:50 
===========================================

EDIT: I would like to mention i am new to programming forums, i screwed this one up as i was frustrated, and really didn't have a direct question. I hope i can improve my manners in the future.

Sorry MCM

===========================================


So let me start out with i am new to C# but not to programming in general. Mostly PHP background.

That being said, i am currently designing "Client", "Server" application. The server reads the COM port for a string, parse's it, inserts it into the database, then sends the client the id of the database entry over Asynchronous TCP. This happens randomly there is no rhyme or reason for when the Serial stream is received.

That being said, it is very important that the TCP transfer of the id is not being delayed at all, seconds really count in this application.

The problem I am having is users are logging off their computer and "Force Closing" the client before it has a chance to send the disconnect command to the server. When this happens the client cannot reconnect until i reset the server's client list.

I would like to implement a "Heartbeat" command, lets say server sends ping to a number of clients (currently three for QA, eventually between 50-100 clients) and the client returns pong meaning the connection is alive. If the client fails to respond within the limit (say 30 seconds to a minute) i would like to remove it from the client list.

But once again this cannot interrupt the main function of this software which is sending the id to the clients and would have to run as a background thread.

I am not familiar enough with background threads (or threads in general really) to make this happen, and after a week of reading and research i am still unsure of my ability to do such a thing within a reasonable amount of time.

I seek help in this matter, if anyone could direct me to a good article, or give me a snippet to start with i would greatly appreciate it.

This section of code is based heavily upon the following article:
A Chat Application Using Asynchronous TCP Sockets[^]

This is probably the reason for me not understanding this as well as i should, i cheated and manipulated this code to do what i needed. I didn't see the need to reinvent the wheel to send a couple digits over TCP, a few times a day.

Let me also note that this "Server Code" runs as a windows service on a server, the client is a Windows Form application.

In the Following Code the sendHeartBeat() method and command.Heartbeat have not actually been implemented, they are the start of my code for it.

Also i have removed the logging code for ease of reading, as my logging methods are a little robust but work well for my needs.

the server side TCP Class code is as follows:

C#
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace mgMapsServer.Classes
{

    enum Command
    {
        Login,      //Log into the server
        Logout,     //Logout of the server
        callLog,    //Sends Call Log ID
        heartbeat,
        Reset,      //Command to Reset All Connections
        Null        //No command

    }

    public class TCPConnector
    {
        //The ClientInfo structure holds 
        //the required information about every
        //client connected to the server
        struct ClientInfo
        {
            //Socket of the client
            public Socket socket;
            //Name by which the user logged into the chat room
            public string strName;
        }
        struct HBInfo
        {
            public Socket socket;
            public int index;
        }

        //The collection of all clients logged 
        //into the room (an array of type ClientInfo)
        ArrayList clientList;

        //The main socket on which the server listens to the clients
        Socket serverSocket;

        //Heartbeat Container
        ArrayList HeartbeatList;

        byte[] byteData = new byte[1024];

        public TCPConnector()
        {
            clientList = new ArrayList();
            HeartbeatList = new ArrayList();

            try
            {
                serverSocket = new Socket(AddressFamily.InterNetwork,
                                          SocketType.Stream,
                                          ProtocolType.Tcp);


                IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, Convert.ToInt32(Library.sqlVars("serverPort")));

                //Bind and listen on the given address
                serverSocket.Bind(ipEndPoint);
                serverSocket.Listen(4);

                //Accept the incoming clients
                serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);
				\*Logging Code*\
            }
            catch (Exception ex) { \*Logging Code*\ }
            }
        }



        private void OnAccept(IAsyncResult ar)
        {
            try
            {
                Socket clientSocket = serverSocket.EndAccept(ar);

                //Start listening for more clients
                serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);

                //Once the client connects then start 
                //receiving the commands from her
                clientSocket.BeginReceive(byteData, 0,
                    byteData.Length, SocketFlags.None,
                    new AsyncCallback(OnReceive), clientSocket);
            }
            catch (Exception ex)  { \*Logging Code*\ }
        }



        private void OnReceive(IAsyncResult ar)
        {
            try
            {
                Socket clientSocket = (Socket)ar.AsyncState;
                clientSocket.EndReceive(ar);

                //Transform the array of bytes received from the user into an
                //intelligent form of object Data
                Data msgReceived = new Data(byteData);

                //We will send this object in response the users request
                Data msgToSend = new Data();

                //byte[] message;

                //If the message is to login, logout, or simple text message
                //then when send to others the type of the message remains the same
                msgToSend.cmdCommand = msgReceived.cmdCommand;
                msgToSend.strName = msgReceived.strName;

                switch (msgReceived.cmdCommand)
                {
                    case Command.heartbeat:

                        break;
                    case Command.Reset:
                        \*Logging Code*\
                        int rIndex = 0;
                        foreach (ClientInfo client in clientList)
                        {
                            clientList.RemoveAt(rIndex);
                            ++rIndex;
                        }
                        break;

                    case Command.Login:

                        //When a user logs in to the server then we add her to our
                        //list of clients

                        ClientInfo clientInfo = new ClientInfo();
                        clientInfo.socket = clientSocket;
                        clientInfo.strName = msgReceived.strName;

                        clientList.Add(clientInfo);

                        //Set the text of the message that we will broadcast to all users
                        msgToSend.strMessage = "<<<" + msgReceived.strName + " has Connected to the Server>>>";
                        break;

                    case Command.Logout:

                        //When a user wants to log out of the server then we search for her 
                        //in the list of clients and close the corresponding connection

                        int nIndex = 0;
                        foreach (ClientInfo client in clientList)
                        {
                            if (client.socket == clientSocket)
                            {
                                clientList.RemoveAt(nIndex);
                                break;
                            }
                            ++nIndex;
                        }

                        clientSocket.Close();

                        msgToSend.strMessage = "<<<" + msgReceived.strName + " has Disconnected from the server>>>";
                        break;
                }

                if ((msgReceived.cmdCommand != Command.heartbeat) || (msgReceived.cmdCommand != Command.heartbeat))
                {
                     \*Logging Code*\
                }
                if (msgReceived.cmdCommand != Command.Logout) { clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnReceive), clientSocket); }
            }
            catch (Exception ex)  { \*Logging Code*\ }
        }

        public string callLogIDSender
        {
            get { return null; }
            set { SendcallLogID(value); }
        }

        public void SendcallLogID(string ID)
        {
            try
            {
                Data msgToSend = new Data();
                byte[] message;
                msgToSend.cmdCommand = Command.callLog;
                msgToSend.strMessage = ID;
                message = msgToSend.ToByte();

				\*Logging Code*\
		
                foreach (ClientInfo clientInfo in clientList)
                {
                    clientInfo.socket.BeginSend(message, 0, message.Length, SocketFlags.None,
                        new AsyncCallback(OnSend), clientInfo.socket);
                }
            }
            catch (Exception ex) { \*Logging Code*\ }
        }

        public void sendHeartBeat()
        {
            try
            {
                Data msgToSend = new Data();
                byte[] message;
                msgToSend.cmdCommand = Command.heartbeat;
                msgToSend.strMessage = null;
                message = msgToSend.ToByte();
                int nIndex = 0;
                foreach (ClientInfo clientInfo in clientList)
                {
                    HBInfo tempHB = new HBInfo();
                    tempHB.index = nIndex;
                    tempHB.socket = clientInfo.socket;
                    HeartbeatList.Add(tempHB);
                    clientInfo.socket.BeginSend(message, 0, message.Length, SocketFlags.None,
                    new AsyncCallback(OnSend), clientInfo.socket);
                    
                    ++nIndex;
                       
                }
            }
            catch (Exception e) { \*Logging Code*\ }
        }

        public void OnSend(IAsyncResult ar)
        {
            try
            {
                Socket client = (Socket)ar.AsyncState;
                client.EndSend(ar);
            }
            catch (Exception ex) 
            {
                \\Logging Code
            }
        }
    }

    //The data structure by which the server and the client interact with 
    //each other
    class Data
    {
        //Default constructor
        public Data()
        {
            this.cmdCommand = Command.Null;
            this.strMessage = null;
            this.strName = null;
        }

        //Converts the bytes into an object of type Data
        public Data(byte[] data)
        {
            //The first four bytes are for the Command
            this.cmdCommand = (Command)BitConverter.ToInt32(data, 0);

            //The next four store the length of the name
            int nameLen = BitConverter.ToInt32(data, 4);

            //The next four store the length of the message
            int msgLen = BitConverter.ToInt32(data, 8);

            //This check makes sure that strName has been passed in the array of bytes
            if (nameLen > 0)
                this.strName = Encoding.UTF8.GetString(data, 12, nameLen);
            else
                this.strName = null;

            //This checks for a null message field
            if (msgLen > 0)
                this.strMessage = Encoding.UTF8.GetString(data, 12 + nameLen, msgLen);
            else
                this.strMessage = null;
        }

        //Converts the Data structure into an array of bytes
        public byte[] ToByte()
        {
            List<byte> result = new List<byte>();

            //First four are for the Command
            result.AddRange(BitConverter.GetBytes((int)cmdCommand));

            //Add the length of the name
            if (strName != null)
                result.AddRange(BitConverter.GetBytes(strName.Length));
            else
                result.AddRange(BitConverter.GetBytes(0));

            //Length of the message
            if (strMessage != null)
                result.AddRange(BitConverter.GetBytes(strMessage.Length));
            else
                result.AddRange(BitConverter.GetBytes(0));

            //Add the name
            if (strName != null)
                result.AddRange(Encoding.UTF8.GetBytes(strName));

            //And, lastly we add the message text to our array of bytes
            if (strMessage != null)
                result.AddRange(Encoding.UTF8.GetBytes(strMessage));

            return result.ToArray();
        }

        public string strName;      //Name by which the client logs into the room
        public string strMessage;   //Message text
        public Command cmdCommand;  //Command type (login, logout, send message, etcetera)
    }


modified 31-May-15 3:31am.

AnswerRe: TCP Heartbeat background Thread Pin
Eddy Vluggen29-May-15 2:57
professionalEddy Vluggen29-May-15 2:57 
GeneralRe: TCP Heartbeat background Thread Pin
MooKowMyke29-May-15 7:57
MooKowMyke29-May-15 7:57 
GeneralRe: TCP Heartbeat background Thread Pin
Eddy Vluggen29-May-15 11:16
professionalEddy Vluggen29-May-15 11:16 
GeneralRe: TCP Heartbeat background Thread Pin
MooKowMyke30-May-15 21:26
MooKowMyke30-May-15 21:26 
QuestionWhy Can't I use asp.net controls with mvc? Pin
Dolly Nimavat27-May-15 20:42
Dolly Nimavat27-May-15 20:42 
AnswerRe: Why Can't I use asp.net controls with mvc? PinPopular
dan!sh 27-May-15 20:49
professional dan!sh 27-May-15 20:49 
AnswerRe: Why Can't I use asp.net controls with mvc? Pin
F-ES Sitecore27-May-15 23:14
professionalF-ES Sitecore27-May-15 23:14 
AnswerRe: Why Can't I use asp.net controls with mvc? Pin
L Viljoen28-May-15 3:20
professionalL Viljoen28-May-15 3:20 
GeneralRe: Why Can't I use asp.net controls with mvc? Pin
F-ES Sitecore28-May-15 5:03
professionalF-ES Sitecore28-May-15 5:03 
GeneralRe: Why Can't I use asp.net controls with mvc? Pin
L Viljoen28-May-15 19:59
professionalL Viljoen28-May-15 19:59 
QuestionSource not available Pin
Dolly Nimavat27-May-15 20:40
Dolly Nimavat27-May-15 20:40 
AnswerRe: Source not available Pin
dan!sh 27-May-15 20:46
professional dan!sh 27-May-15 20:46 
Questionsyntax SIM card registration with the network through the AT commands ? Pin
Member 245846727-May-15 18:56
Member 245846727-May-15 18:56 
AnswerRe: syntax SIM card registration with the network through the AT commands ? Pin
OriginalGriff27-May-15 19:23
mveOriginalGriff27-May-15 19:23 
QuestionGet the phone number SIM Imel with C#? Pin
Member 245846727-May-15 18:45
Member 245846727-May-15 18:45 
AnswerRe: Get the phone number SIM Imel with C#? Pin
OriginalGriff27-May-15 19:23
mveOriginalGriff27-May-15 19:23 
Questionconvert string[]/byte to bool[] Pin
hasan hadi27-May-15 16:47
hasan hadi27-May-15 16:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.