简体   繁体   中英

Manage connected TCP clients

I have a TCP IP server application that accepts multiple clients and handle their requests.

One of the cases that I need to handle is sending a late response to a client, to be more specific, here is my design details and protocol:

A) A client send a request to do a job, and server received it successfully and starts that job.

B) Server, after a long time, needs to search for that client connection and tell him that his job is completed

My approach is as following:

  • On client connection, I generate a new instance of a Class that holds the TcpClient client instance that just connected, and a unique token, so that I can trace client requests and reply to him asynchronously, lets call this class MyConnectedClient .

  • Then, I insert this MyConnectedClient instance into a Hashtable of clients, the unique token is his Key, and the value is the instance of MyConnectedClient


  • Now, when a job is completed, depending on the client token passed to the job, I can retrieve the client from my connected clients list and send a memo to the client.

  • Also, when client connection dies, I raise an event and sends the token along with it, so my server will remove the MyConnectedClient instance from the connected clients list.


Basically, this is my user management design, as I said, it is working fine and enough to my needs, but the question is, Is there a better way to handle the connected clients ?

To remove dead clients or find a client that made a request earlier ?

Complete Sample Code Below:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Collections;

namespace TCPIPIPC.Server
{
    public class Server
    {
        int publicToken = 0;

        public class ConnectedClient
        {
            public TcpClient tcpClient;
            public DateTime connectedSince;
            public int token;
        }

        Hashtable ClientList;

        #region Variable declaration
        /// <summary>
        /// Main TCP listener
        /// </summary>
        private TcpListener tcpListener;

        /// <summary>
        /// Main server thread
        /// </summary>
        private Thread listenThread;

        /// <summary>
        /// Event handler for received message from the server
        /// </summary>
        /// <param name="message"></param>
        public delegate void ServerMessageEventHandler(string message, ConnectedClient client);

        /// <summary>
        /// Event handler for connected client to the server
        /// </summary>
        /// <param name="tcpClient"></param>
        public delegate void clientconnectedEventHandler(ConnectedClient client);

        /// <summary>
        /// Event to be raised when data received from the server
        /// </summary>
        public event ServerMessageEventHandler MessageReceived;

        /// <summary>
        /// Event to be raised when a client is Connected/Disconnected to the server
        /// </summary>
        public event clientconnectedEventHandler ClientConnected;
        public event clientconnectedEventHandler ClientDisconnected;

        public IList Items;
        #endregion

        /// <summary>
        /// Constructor, Server initialization
        /// </summary>
        public Server(IPAddress listenerAddress, int listenerPort)
        {
            ClientList = new Hashtable();
            ClientDisconnected += new clientconnectedEventHandler(Server_ClientDisconnected);
            this.tcpListener = new TcpListener(listenerAddress, listenerPort); //new TcpListener(IPAddress.Any, 3000);
            this.listenThread = new Thread(new ThreadStart(ListenForClients));
            this.listenThread.Start();
        }

        /// <summary>
        /// Remove disconnected clients
        /// </summary>
        /// <param name="client"></param>
        void Server_ClientDisconnected(Server.ConnectedClient client)
        {
            if (ClientList.ContainsKey(client.token))
            {
                ClientList.Remove(client.token);
            }
        }

        /// <summary>
        /// Main listener thread start
        /// </summary>
        private void ListenForClients()
        {
            this.tcpListener.Start();
            while (true)
            {
                //blocks until a client has connected to the server
                TcpClient client = this.tcpListener.AcceptTcpClient();

                var connecteItem = new ConnectedClient();

                connecteItem.tcpClient = client;
                connecteItem.connectedSince = DateTime.Now;
                connecteItem.token = publicToken++;

                //create a thread to handle communication 
                //with connected client
                Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
                clientThread.Start(client);

                //Raise client connected event
                if (ClientConnected != null)
                {
                    ClientConnected(connecteItem);
                }
            }
        }

        /// <summary>
        /// Client communication handler
        /// </summary>
        /// <param name="client">the received connection from the client of type TcpClient</param>
        private void HandleClientComm(object client)
        {
            ConnectedClient currentClient = (ConnectedClient)client;
            TcpClient tcpClient = currentClient.tcpClient;
            NetworkStream clientStream = tcpClient.GetStream();

            byte[] message = new byte[4096];
            int bytesRead;

            while (true)
            {
                bytesRead = 0;

                try
                {
                    //blocks until a client sends a message
                    bytesRead = clientStream.Read(message, 0, 4096);
                }
                catch
                {
                    //a socket error has occurred
                    break;
                }

                if (bytesRead == 0)
                {
                    //the client has disconnected from the server
                    break;
                }

                //message has successfully been received
                ASCIIEncoding encoder = new ASCIIEncoding();

                //Raise message received event
                if (MessageReceived != null)
                {
                    MessageReceived(encoder.GetString(message, 0, bytesRead), currentClient);//This will be caught by a parent worker who will start a job based on this request 
                }

                //System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));
            }

            tcpClient.Close();

            if (ClientDisconnected != null)
            {
                ClientDisconnected(currentClient);
            }
        }

        /// <summary>
        /// This method sends a message to a connected client
        /// </summary>
        /// <param name="tcpClient">The connected TcpClient client instance to send a message to</param>
        /// <param name="message">The message to send to the client</param>
        public void SendMessage(TcpClient tcpClient, string message)
        {
            NetworkStream clientStream = tcpClient.GetStream();
            ASCIIEncoding encoder = new ASCIIEncoding();
            byte[] buffer = encoder.GetBytes(message);

            clientStream.Write(buffer, 0, buffer.Length);
            clientStream.Flush();
        }
    }
}

Please not that code above is not fully finalized, but it illustrates the idea

Just associate the client socket with the Job, and have the job task write the response to that socket. If that fails, the client has disconnected. You don't need all this other jazz really.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM