簡體   English   中英

管理連接的TCP客戶端

[英]Manage connected TCP clients

我有一個TCP IP服務器應用程序,可以接受多個客戶端並處理他們的請求。

我需要處理的一種情況是向客戶端發送延遲響應,更具體地說,這是我的設計細節和協議:

A)客戶端發送請求執行一項工作,服務器成功接收到該請求並啟動該工作。

B)服務器很長一段時間后,需要搜索該客戶端連接,並告訴他工作已完成

我的方法如下:

  • 在客戶端連接上,我生成一個類的新實例,該實例包含剛剛連接的TcpClient客戶端實例以及一個唯一的令牌,以便我可以跟蹤客戶端請求並異步答復他,讓我們將該類稱為MyConnectedClient

  • 然后,我將此MyConnectedClient實例插入到客戶端的哈希表中,唯一的令牌是他的Key,而值是MyConnectedClient的實例


  • 現在,當作業完成時,根據傳遞給該作業的客戶令牌,我可以從連接的客戶列表中檢索該客戶並將備忘錄發送給該客戶。

  • 另外,當客戶端連接中斷時,我引發一個事件並與之一起發送令牌,因此我的服務器將從連接的客戶端列表中刪除MyConnectedClient實例。


基本上,這就是我的用戶管理設計,正如我所說的那樣,它可以很好地滿足我的需求,但是問題是,是否有更好的方法來處理連接的客戶端?

要刪除死掉的客戶還是找到更早提出請求的客戶?

完整的示例代碼如下:

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();
        }
    }
}

請注意,上面的代碼還沒有完全完成,但是它說明了這個想法

只需將客戶端套接字與Job關聯,然后讓job任務將響應寫入該套接字即可。 如果失敗,則客戶端已斷開連接。 您真的不需要所有其他爵士樂。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM