我需要构建一个应用程序(服务器)来处理通过 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();
}
}
}
很多关于这个主题的文章人们都在使用套接字。我还读到 .net 4.5 async/await 是实现解决方案的最佳方式。
我想确保利用 .net 中的最新功能(如果有帮助,甚至是 4.5.2)并构建一个至少可以处理 2000 个连接的服务器。有人可以建议吗?
非常感谢!
最佳答案
好的,我们需要修复一些 API 使用错误,然后是创建过多线程的主要问题。众所周知,许多连接只能通过异步 IO 有效处理。数百个连接算作“太多”。
您的客户端处理循环必须是异步的。重写 HandleClientComm
,使其使用异步套接字 IO。这很容易等待。您需要在网上搜索“.net socket await”。
您可以继续使用同步接受调用。那里没有缺点。保留简单的同步代码。仅使那些具有重要 avgWaitTime * countPerSecond
产品的调用异步。通常,这将是所有套接字调用。
您假设 DataAvailable
返回任何给定消息中的字节数。 TCP 不保留消息边界。你需要自己做。 DataAvailable
值几乎没有意义,因为它可能低估了 future 将到达的真实数据。
通常使用更高级别的序列化协议(protocol)会更好。例如,带有长度前缀的 protobuf。不要使用 ASCII。您可能已经这样做了,因为您不知道如何使用“真实”编码来做到这一点。
使用 using
处理所有资源。不要使用非泛型 Queue
类。不要刷新流,这对套接字没有任何作用。
你为什么要 sleep ?
关于c# - 在 .net 中处理大量 TCP 客户端连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31904039/