【发布时间】:2010-12-29 14:36:18
【问题描述】:
我已经创建了简单的 tcp 服务器 - 它运行良好。
当我们切换到压力测试时问题就开始了——因为我们的服务器应该处理许多并发打开的套接字——我们创建了一个压力测试来检查这一点。 不幸的是,当并发打开的套接字数量在 100 左右时,看起来服务器正在阻塞,无法及时响应新的连接请求。
我们已经尝试了几种类型的服务器 - 并且都产生了相同的行为。
服务器:可以类似于本文中的示例(都产生相同的行为)
How to write a scalable Tcp/Ip based server
这是我们正在使用的代码 - 当客户端连接时 - 服务器将挂起以保持套接字处于活动状态。
enter code here
公共类服务器
{
private static readonly TcpListener listener = new TcpListener(IPAddress.Any, 2060);
public Server()
{
listener.Start();
Console.WriteLine("Started.");
while (true)
{
Console.WriteLine("Waiting for connection...");
var client = listener.AcceptTcpClient();
Console.WriteLine("Connected!");
// each connection has its own thread
new Thread(ServeData).Start(client);
}
}
private static void ServeData(object clientSocket)
{
Console.WriteLine("Started thread " + Thread.CurrentThread.ManagedThreadId);
var rnd = new Random();
try
{
var client = (TcpClient)clientSocket;
var stream = client.GetStream();
byte[] arr = new byte[1024];
stream.Read(arr, 0, 1024);
Thread.Sleep(int.MaxValue);
}
catch (SocketException e)
{
Console.WriteLine("Socket exception in thread {0}: {1}", Thread.CurrentThread.ManagedThreadId, e);
}
}
}
压力测试客户端:是一个简单的 tcp 客户端,一个接一个地循环和打开套接字
class Program
{
static List<Socket> sockets;
static private void go(){
Socket newsock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint iep = new IPEndPoint(IPAddress.Parse("11.11.11.11"), 2060);
try
{
newsock.Connect(iep);
}
catch (SocketException ex)
{
Console.WriteLine(ex.Message );
}
lock (sockets)
{
sockets.Add(newsock);
}
}
static void Main(string[] args)
{
sockets = new List<Socket>();
//int start = 1;// Int32.Parse(Console.ReadLine());
for (int i = 1; i < 1000; i++)
{
go();
Thread.Sleep(200);
}
Console.WriteLine("press a key");
Console.ReadKey();
}
}
}
有没有简单的方法来解释这种行为?如果 TCP 服务器会产生更好的结果,也许 c++ 实现?也许这实际上是一个客户端问题?
欢迎任何评论!
报价
【问题讨论】:
-
你在什么操作系统上测试?你不应该为每个连接都创建一个新线程,你应该考虑使用异步接口来实现一般的可伸缩性,请参阅 BeginAccept、BeginReceive 等。
-
win 7. 我知道异步方法更可取。但是,上述行为发生在我尝试过的任何服务器实现上——包括回调 ..
-
您不应为每个客户端启动一个线程。这不能很好地扩展,因为该过程将花费更多的时间来安排而不是实际工作。请改用线程池。您还应该在使用 Streams 后关闭它们(查看 C# using 模式)。
-
首先,正如其他人所指出的,不要为每个连接创建一个线程。使用异步 API。即使您的服务器没有做任何其他事情(例如,提供内容),您在任何 32 位进程中都将被限制为 around 2000 threads。其次,请编辑您的问题,提供以下信息:操作系统(是的,这非常重要)和您收到的错误消息(以及您在哪里获得)。
标签: c# .net sockets winsock winsock2