Jam*_*mes 13 c# sockets multithreading tcp
我试图通过跨多个线程的请求命中它来对网站进行性能测试.每个线程执行n次.(在for循环中)
但是,我遇到了问题.特别是WebException("无法连接到远程服务器")与内部异常:
无法执行套接字上的操作,因为系统缺少足够的缓冲区空间或者队列已满,因此127.0.0.1:52395
我试图在每个线程500次迭代时运行100个线程.
最初我HttpWebRequest
在System.Net 中使用来向服务器发出GET请求.目前我正在使用,WebClient
因为我假设每次迭代使用一个新的套接字(所以在短时间内100*500套接字).我假设WebClient(每个线程实例化一次)只会使用一个套接字.
我不需要一次打开50 000个套接字,因为我想发送GET请求,接收响应并关闭套接字,释放它以便在下一个循环迭代中使用.我明白这将是一个问题
但是,即使使用WebClient,也会请求一堆套接字,从而在TIME_WAIT
模式下产生一堆套接字(使用netstat检查).这会导致其他应用程序(如Internet浏览器)挂起并停止运行.
我可以用更少的迭代和/或更少的线程来操作我的测试,因为看起来套接字最终会退出这个TIME_WAIT状态.但是,这不是一个解决方案,因为它没有充分测试Web服务器的功能.
题:
在每次线程迭代后如何显式关闭套接字(从客户端)以防止TIME_WAIT状态和套接字耗尽?
码:
包装HttpRequest的类
编辑:在使用中包装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 ) ) {
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的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();
}
Run Code Online (Sandbox Code Playgroud)
spe*_*der 12
你了解TIME_WAIT的目的吗?这是一段时间,重用端口是不安全的,因为之前的事务中丢失的数据包(已成功重新传输)可能仍在该时间段内传递.
你可以在某个地方的注册表中调整它,但我怀疑这是否是明智的下一步.
我在测试环境中创建实际负载的经验证明非常令人沮丧.当然从localhost运行你的负载测试器绝对不现实,我使用.net http apis进行的大多数网络测试似乎需要客户端比服务器本身更多的grunt.
因此,最好转移到第二台机器上,以便在服务器上产生负载......但是,国内路由设备很少能够支持任何接近连接数的地方,这会导致编写良好的服务器上的任何负载应用程序,所以现在您还需要升级您的路由/交换设备!
最后,围绕.net Http客户端API,我遇到了一些非常奇怪和意想不到的性能问题.在一天结束时,他们都使用HttpWebRequest来完成繁重的工作.IMO它的性能远远不够.即使在异步调用API时,DNS也是同步的(尽管如果您只是从单个主机请求,这不是问题),并且在持续使用之后CPU使用量会逐渐增加,直到客户端变为CPU受限而不是IO约束为止.如果你想要产生持续和沉重的负载,任何依赖于HttpWebRequest的请求重的应用程序都是IMO的一项虚假投资.
总而言之,这是一项相当棘手的工作,最终只能在野外证明,除非你有足够的现金花在更好的装备上.
[提示:我使用异步Socket apis和第三方DNS客户端库编写的自己客户端的性能更好]