我需要构建一个应用程序(服务器)来处理通过TCP从客户端发送的数据。我必须能够支持(至少)2000个连接。我已经尝试编写TCP服务器,但我发现当我开始达到600/700连接时,我服务器的响应速度很慢(随着接收越来越多的连接,它实际上会随着时间的推移而减慢)。我通常不会编写网络代码,所以我确信有很多概念我还没有完全理解,可以改进。
我的服务器的主要目的是:
这需要为所有客户实现。以下是我实施的代码:
private readonly TcpListener tcpListener;
private readonly Thread listenThread;
private bool run = true;
public Server()
{
this.tcpListener = new TcpListener(IPAddress.Any, AppSettings.ListeningPort); //8880 is default for me.
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
this.tcpListener.Start();
while (run) {
TcpClient client = this.tcpListener.AcceptTcpClient();
//create a thread to handle communication with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
private void HandleClientComm(object client)
{
Queue responseMessages = new Queue();
while (run)
{
try
{
lastMessage = clientStream.GetMessage();
if (lastMessage.Length > 0)
{
// Process logic here...
//an item may be added to the response queue, depending on logic.
}
if (responseMessages.Count > 0)
{
clientStream.WriteMessage(msg);
clientStream.Flush();
// sleep for 250 milliseconds (or whats in the config).
Thread.Sleep(AppSettings.MessageSendDelayMilliseconds);
}
}
catch (Exception ex)
{
break;
}
}
tcpClient.Close();
}
最后,这是我写的一个扩展课来帮助我:
namespace System.Net.Sockets
{
using System.Text;
public static class NetworkSteamExtension
{
private static readonly ASCIIEncoding Encoder = new ASCIIEncoding();
public static string GetMessage(this NetworkStream clientStream)
{
string message = string.Empty;
try
{
byte[] bMessage = new byte[4068];
int bytesRead = 0;
while (clientStream.DataAvailable)
{
bytesRead = clientStream.Read(bMessage, 0, 4068);
message += Encoder.GetString(bMessage, 0, bytesRead);
}
}
catch (Exception)
{
}
return message;
}
public static void WriteMessage(this NetworkStream clientStream, string message)
{
byte[] buffer = Encoder.GetBytes(message);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
}
}
关于这个主题的很多文章人们正在使用套接字。我还读到.net 4.5 async / await是实现解决方案的最佳方式。
我想确保我利用.net中的最新功能(如果它有帮助,甚至4.5.2)并构建一个可以处理至少2000个连接的服务器。有人可以建议吗?
非常感谢!
答案 0 :(得分:2)
好的,我们需要修复一些API使用错误,然后解决创建太多线程的主要问题。众所周知,许多连接只能通过异步IO有效处理。数百个连接被视为“太多”。
您的客户端处理循环必须是异步的。重写HandleClientComm
以便它使用异步套接字IO。这很容易等待。您需要在网上搜索“.net socket await”。
您可以继续使用同步接听电话。那里没有缺点。保留简单的同步代码。只允许那些具有重要avgWaitTime * countPerSecond
产品的调用异步。这通常是所有套接字调用。
您假设DataAvailable
返回任何给定消息中的字节数。 TCP不保留消息边界。你需要自己做。 DataAvailable
值几乎没有意义,因为它可能会低估将来到达的真实数据。
通常使用更高级别的序列化协议会更好。例如,带有长度前缀的protobuf。不要使用ASCII。您可能只是因为您不知道如何使用“真实”编码来完成此操作。
使用using
处理所有资源。不要使用非泛型Queue
类。不要刷新流,这对套接字没有任何作用。
你为什么睡觉?