【发布时间】:2012-07-19 21:16:47
【问题描述】:
我正在尝试通过跨多个线程的请求来对网站进行性能测试。每个线程执行 n 次。 (在 for 循环中)
但是,我遇到了问题。特别是带有内部异常的 WebException(“无法连接到远程服务器”):
无法对套接字执行操作,因为系统 缺少足够的缓冲区空间或因为队列已满 127.0.0.1:52395
我正在尝试以每个线程 500 次迭代运行 100 个线程。
最初我在 System.Net 中使用HttpWebRequest 向服务器发出 GET 请求。目前我正在使用WebClient,因为我假设每次迭代都使用一个新的套接字(所以在短时间内有 100 * 500 个套接字)。我假设 WebClient (每个线程实例化一次)只会使用一个套接字。
我不需要一次打开 50 000 个套接字,因为我想发送 GET 请求、接收响应并关闭套接字,将其释放以供下一次循环迭代使用。我知道这将是一个问题
但是,即使使用 WebClient,也会请求一组套接字,从而导致一组套接字处于 TIME_WAIT 模式(使用 netstat 检查)。这会导致其他应用程序(如互联网浏览器)挂起并停止运行。
我可以用更少的迭代和/或更少的线程来运行我的测试,因为看起来套接字最终会退出这个 TIME_WAIT 状态。但是,这不是一个解决方案,因为它没有充分测试 Web 服务器的能力。
问题:
如何在每次线程迭代后显式关闭套接字(从客户端)以防止 TIME_WAIT 状态和套接字耗尽?
代码:
包装 HttpRequest 的类
编辑: 在 using 中包装了 WebClient,因此每次迭代都会实例化、使用和处置一个新的 WebClient。问题依然存在。
public sealed class HttpGetTest : ITest {
private readonly string m_url;
public HttpGetTest( string url ) {
m_url = url;
}
void ITest.Execute() {
using (WebClient webClient = new WebClient()){
using( Stream stream = webClient.OpenRead( m_url ) ) {
}
}
}
}
我的 ThreadWrapperClass 中创建新线程的部分:
public void Execute() {
Action Hammer = () => {
for( int i = 1; i <= m_iterations; i++ ) {
//Where m_test is an ITest injected through constructor
m_test.Execute();
}
};
ThreadStart work = delegate {
Hammer();
};
Thread thread = new Thread( work );
thread.Start();
}
【问题讨论】:
-
要考虑的一件事是不要使用“从消防水带中喝水”的方法进行测试。您应该慢慢开始并将请求/秒增加到一个固定的最大值,以正确测试您的系统。然后,您可以在多次运行中增加最大值,直到找到极限。无限的网络请求不会告诉你什么。
-
请记住,只有大约 65000 个可用端口,并非所有端口都可用于传出连接。因此,您需要使用多个 IP/NIC 来执行您尝试执行的 50000 个连接
-
@StefanH 我知道如果我正在执行大量线程,这将是一个问题,但是,一旦循环的迭代完成,我就不再需要套接字了,但它仍然存在,导致下一次迭代打开一个新的。我正在寻找一种方法来防止这种情况发生
-
您正在使用正在返回的流,但不是您的 Web 客户端。您也可以在 WebClient 上尝试使用 using 语句,以便处理它。或在阅读完毕后手动处理。
标签: c# multithreading sockets tcp