При сканировании хостов нужно собрать информацию о них. Все работает, но слишком медленно - C#
Формулировка задачи:
Разработал систему мониторинга. При сканировании хостов нужно собрать информацию о них. Все работает, но слишком медленно. Компьютеров несколько тысяч, а один выключенный компьютер сканируется полторы минуты.
Можно ли как-то уменьшить время сканирования одного порта, которое равно ~21сек. Вещи типа SendTimeout и ReceiveTimeout не помогают. Пробовал сканировать порты с помощью асинхронных сокетов с таймаутом 3 секунды, работает хорошо, однако операционая система по истечени этого времени все равно продолжает ждать ответ. В итоге сканирутся в 50 потоков, а висит их 50 и постоянно увеличивается.
Код обычного сканера:
Код с асинхронными сокетами
struct PortScanStructure
{
public bool Active;
public bool PortOpen;
}
class PortScannerOld
{
public static void Scan(string p_IPAddress, int p_Port, ref PortScanStructure p_PSS)
{
p_PSS.Active = false;
p_PSS.PortOpen = false;
Socket sock;
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.ReceiveTimeout = 500;
sock.SendTimeout = 100;
try
{
sock.Connect(p_IPAddress, p_Port);
}
catch (SocketException se)
{
if (se.ErrorCode == 10061 || se.ErrorCode == 10054)
p_PSS.Active = true;
}
finally
{
if (sock.Connected)
{
p_PSS.Active = true;
p_PSS.PortOpen = true;
sock.Disconnect(false);
}
sock.Close();
}
}
}struct PortScanResult
{
public bool PortActive;
public bool HostActive;
public PortScanResult(bool PortState, bool HostState)
{
PortActive = PortState;
HostActive = HostState;
}
}
class PortScanner
{
private ManualResetEvent TimeoutObject = new ManualResetEvent(false);
private PortScanResult Result = new PortScanResult(false, false);
public PortScanner() { }
~PortScanner()
{
TimeoutObject.Close();
}
public PortScanResult Scan(string host, int port, int timeout)
{
TimeoutObject.Reset();
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.BeginConnect(host, port, ConnectCallback, sock);
TimeoutObject.WaitOne(timeout, false);
return Result;
}
public void ConnectCallback(IAsyncResult AsyncResult)
{
Socket sock = (Socket)AsyncResult.AsyncState;
try
{
sock.EndConnect(AsyncResult);
if (sock.Connected)
{
sock.Shutdown(SocketShutdown.Both);
sock.Disconnect(false);
Result.PortActive = true;
Result.HostActive = true;
}
}
catch (SocketException se)
{
if (se.ErrorCode == 10054 || se.ErrorCode == 10061)
{
Result.PortActive = false;
Result.HostActive = true;
}
}
catch { }
finally
{
sock.Close();
TimeoutObject.Set();
}
}
}Решение задачи: «При сканировании хостов нужно собрать информацию о них. Все работает, но слишком медленно»
textual
Листинг программы
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace portScan2
{
class Program
{
static void Main(string[] args)
{
PortScanner ps = new PortScanner();
ps.Scan("192.168.0.1", 23, 1000);
ps.Scan("192.168.0.1", 80, 1000);
ps.Scan("192.168.0.1", 135, 1000);
ps.Scan("192.168.0.1", 443, 1000);
ps.Scan("192.168.0.1", 8080, 1000);
Console.WriteLine("--->");
Console.Read();
}
}
struct PortScanResult
{
public bool PortActive;
public bool HostActive;
public PortScanResult(bool PortState, bool HostState)
{
PortActive = PortState;
HostActive = HostState;
}
}
class PortScanner
{
private ManualResetEvent TimeoutObject = new ManualResetEvent(false);
private PortScanResult Result = new PortScanResult(false, false);
public PortScanner() { }
~PortScanner()
{
TimeoutObject.Close();
}
public PortScanResult Scan(string host, int port, int timeout)
{
TimeoutObject.Reset();
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.BeginConnect(host, port, ConnectCallback, sock);
TimeoutObject.WaitOne(timeout, false);
sock.Close();
Console.WriteLine("Scan complete");
return Result;
}
public void ConnectCallback(IAsyncResult AsyncResult)
{
Socket sock = (Socket)AsyncResult.AsyncState;
try
{
sock.EndConnect(AsyncResult);
if (sock.Connected)
{
sock.Shutdown(SocketShutdown.Both);
sock.Disconnect(false);
Result.PortActive = true;
Result.HostActive = true;
}
}
catch (SocketException se)
{
if (se.ErrorCode == 10054 || se.ErrorCode == 10061)
{
Result.PortActive = false;
Result.HostActive = true;
}
}
catch { }
finally
{
sock.Close();
TimeoutObject.Set();
}
}
}
}