C# 在.net中处理大量TCP客户端连接
我需要构建一个应用程序(服务器),处理通过TCP从客户端发送的数据。我必须能够支持(至少)2000个连接。我曾尝试编写TCP服务器,但我发现当我开始达到600/700连接时,服务器的响应速度会大大降低(随着接收到越来越多的连接,响应速度实际上会随着时间的推移而降低)。我通常不写网络代码,所以我确信有很多概念我还没有完全理解,可以改进 我的服务器的主要用途是:C# 在.net中处理大量TCP客户端连接,c#,.net,sockets,networking,tcp,C#,.net,Sockets,Networking,Tcp,我需要构建一个应用程序(服务器),处理通过TCP从客户端发送的数据。我必须能够支持(至少)2000个连接。我曾尝试编写TCP服务器,但我发现当我开始达到600/700连接时,服务器的响应速度会大大降低(随着接收到越来越多的连接,响应速度实际上会随着时间的推移而降低)。我通常不写网络代码,所以我确信有很多概念我还没有完全理解,可以改进 我的服务器的主要用途是: 处理从客户端发送的数据并将其存储在sql数据库中 决定(基于) 收到最后一条消息后)应向客户机提供什么样的正确响应 将响应列表和 一次发送
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();
}
}
}
关于这个主题的很多文章人们都在使用套接字。我还了解到.NET4.5Async/await是实现解决方案的最佳方式
我想确保利用.net中的最新功能(如果有帮助的话,甚至是4.5.2),构建一个至少可以处理2000个连接的服务器。有人能提供建议吗
非常感谢 好的,我们需要修复一些API使用错误,然后是创建太多线程的主要问题。众所周知,许多连接只能通过异步IO有效处理。数百个连接被视为“太多” 客户端处理循环必须是异步的。重写HandleClientComm,使其使用异步套接字IO。这很容易等待。您需要在web上搜索“.net套接字等待” 您可以继续使用同步接受调用。没有坏处。保持简单的同步代码。仅对具有重要
avgWaitTime*countPerSecond
产品的调用进行异步。这通常是所有套接字调用
假设DataAvailable
返回任何给定消息中的字节数。TCP不保留消息边界。你需要自己去做。DataAvailable
值几乎没有意义,因为它可能会低估未来将到达的真实数据
通常最好使用更高级别的序列化协议。例如,带有长度前缀的protobuf。不要使用ASCII码。您这样做可能只是因为您不知道如何使用“真实”编码
使用和处理所有资源。不要使用非通用的队列
类。不要刷新流,这对套接字没有任何作用
为什么要睡觉?看起来您为每个客户端连接启动了一个线程。这将是600/700线程在您的进程中,所有需要得到一个时间片。。。。检查你想做的每件事的方法。那么你认为我所需要的只是一行的改变吗?从“TcpClient client=this.tcpListener.AcceptTcpClient();”到“Task client=this.tcpListener.AcceptTcpClientAsync();”?或者还有更多?听起来像是一个潜在的用途。这个框架使它易于扩展并处理异步和线程的所有复杂性。谢谢@usr-你提出了很多(好的)建议!正如我提到的,我对这种类型的编程非常陌生,示例对我非常有帮助!:-)例如,您说过不要使用Queue类-我可以使用哪些替代方案?转换的“真实”编码方式是什么。顺便说一句,睡眠只是为了确保客户端不会因为响应而慌乱(这是我们使用的客户端的一个缺点)。使用Queue
。更好的编码是UTF8,但这更难,因为UTF8字节字符串不能在任意边界上拆分。睡眠-好的,这是一个很好的睡眠案例。使用Task.Delay@usr您让它听起来很简单;-)忙着自己写一本。。。我同意你的观点。。我在做运动时要问的问题。我已经写了代码。。。但我知道有些事情不对劲只是不确定。。。最佳实践。。。我不知道什么味道。。。我相信这是因为它适用于许多线程。。。但我认为线程池可以处理这个问题。你可能有gd参考我可以读。太多的线程意味着你正在阻塞。提出一个问题并在此处留下链接@Seabizkit