我有一个 TCP IP 服务器应用程序,它接受多个客户端并处理他们的请求。
我需要处理的一种情况是向客户发送延迟响应,更具体地说,这是我的设计细节和协议:
A)客户端发送一个请求来完成一项工作,服务器成功接收到它并启动该工作。
B)服务器,过了很长时间,需要搜索那个客户端连接并告诉他他的工作已经完成
我的方法如下:
在客户端连接上,我生成了一个新的 Class 实例,其中包含
TcpClient
刚刚连接的客户端实例和一个唯一的令牌,以便我可以跟踪客户端请求并异步回复他,让我们调用这个类MyConnectedClient
。然后,我把这个
MyConnectedClient
实例插入到clients的一个Hashtable中,唯一的token就是他的Key,value就是他的实例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();
}
}
}
请注意,上面的代码尚未完全确定,但它说明了这个想法