由于现在很难用syn扫描,于是那天另做一个标准tcp扫描的时候发现了一个问题。
本来想象中很简单,就是一个多线程,一个tcpclinet而已。
扫描部分代码如下。多说一句,由于.net下无论tcpclient还是socket都没有connect timeout(连接超时)的设置,网上借鉴了一下别人的用AutoResetEvent的等待做超时,异步连接,如果超时之前连接成功就set(),如果等到100毫秒还没异步连接成功就认为失败。
private void ec(IAsyncResult iar)
{
try
{
TcpClient tc = (TcpClient)iar.AsyncState;
tc.EndConnect(iar);
are.Set();
}
catch { }
}
AutoResetEvent are = new AutoResetEvent(false);
private void ceshi(IPEndPoint ipp)
{
TcpClient tc = new TcpClient();
tc.BeginConnect(ipp.Address, ipp.Port, ec, tc);
are.WaitOne(100);
if (tc.Connected)
{
Console.WriteLine(ipp.ToString());
}
try
{
tc.Close();
}
catch { }
}
就这样一个同样的代码,我直接用Thread开512个线程去执行ceshi这个方法结果,几秒钟cpu100%了卡住了。我用vs2010性能分析工具,说全都是由于BeginConnect EndConnect和Close几个方法占用的cpu。
但是奇怪的是,同样还是上面的代码,用ThreadPool去执行ceshi,同样用512的线程的话,cpu占用率就基本为0,不要怀疑线程池的限制了线程数,我ThreadPool.SetMaxThreads(int.MaxValue, int.MaxValue);了
而且从netstat -ano看,确实是大量的连接,确实是512个线程连接,从路由器中看也是如此。
难道线程池还能优化TcpClient?真是百思不得其解啊。
顺便说一下,如果直接用Thread 512个线程的话,从任务管理器中看,上来就会有512个线程(其实还有一些辅助线程上来600多),而用线程池的话,他会从几十个线程开始2个2个的往上加,最后也达到600多个,稳定到600多线程,保证512个线程去连接是没有问题的。
所以上来说一下,做这种大量网络操作的同志们还是用线程池吧。