管理连接的TCP客户端

本文关键字:客户端 TCP 连接 管理 | 更新日期: 2023-09-27 18:20:23

我有一个TCP/IP服务器应用程序,它接受多个客户端并处理它们的请求。

我需要处理的一种情况是向客户端发送延迟响应,更具体地说,以下是我的设计细节和协议:

A) 客户端发送一个作业请求,服务器成功接收并启动该作业。

B) 服务器,在很长一段时间后,需要搜索该客户端连接,并告诉他他的工作已经完成

我的方法如下:

  • 在客户端连接上,我生成一个新的Class实例,该实例包含刚刚连接的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();
        }
    }
}

请注意,上面的代码还没有完全定稿,但它说明了

管理连接的TCP客户端

的想法

只需将客户端套接字与作业相关联,并让作业任务将响应写入该套接字。如果失败,则表明客户端已断开连接。你真的不需要其他爵士乐。