C# Выполнение сканирования портов TCP без исключения Out of Memory
Поэтому я пытаюсь сканировать открытые порты с заданным IP-адресом. Я нашел несколько примеров, но получаю исключение "Недостаточно памяти", если я задаю 65535 задач. Я хотя хм, может быть, это слишком много. Так что я попробовал 2000.. еще много. 1000? ДА.
Но, по-видимому, проблема заключается в "TaskCreationOptions.LongRunning". Если я попробую TaskCreationOptions.None это делает все, но очень медленно! как моя бабушка может сканировать порты гораздо быстрее.
И забавно то, что если я отлаживаю (F5 - Visual studio), то это работает, но если я запускаю программу без отладки, это не так. Таким образом, я могу сканировать 1000 портов за несколько секунд, но как мне реализовать очередь?
Вот мой код Я попытался зациклить, выполнить на финише и т.д.. ничего:(
Любая помощь оценивается, спасибо заранее!
private void ScanPorts()
{
int startPort = 1000;
int endPoint = 65535;
myProgressBar.Value = 0;
myProgressBar.Step = 1;
myProgressBar.Maximum = endPoint - startPort + 1;
var scans = from i in Enumerable.Range(startPort, endPoint - startPort + 1)
select ScanSinglePortTask(i).ContinueWith(t => Response(t.Result), TaskScheduler.FromCurrentSynchronizationContext());
var tasks = scans.ToArray();
}
private Task<string> ScanSinglePortTask(int currPort)
{
return Task.Factory.StartNew(() =>
{
try
{
using (var tcpportScan = new TcpClient())
{
tcpportScan.SendTimeout = 10;
tcpportScan.Connect("127.0.0.1", (int)currPort);
}
return "IP: 127.0.0.1 - Port " + currPort + " open.\n";
}
catch (Exception)
{
return "IP: 127.0.0.1 - Port " + currPort + " closed.\n";
}
}, TaskCreationOptions.LongRunning);
}
private void Response(object message)
{
lblProgress.Text = ((string)message);
listBox1.Items.Add(((string)message));
listBox1.SelectedIndex = listBox1.Items.Count - 1;
myProgressBar.PerformStep();
}
РЕДАКТИРОВАТЬ
РЕШЕНИЕ ТЕМПЕРАТУРЫ
Поэтому мне удалось избавиться от исключения "Недостаточно памяти", установив целевую платформу с x86 на x64.
Таким образом, у x86 есть 2 гигабайта виртуальной памяти, а у x64 более 6 Тб + виртуальная память.
Это не решение, если вы спросите меня, а временное.
НОВОЕ РЕШЕНИЕ
x86 и x64 бит совместимы!
Система очередей, которую я внедрил, ответов на этот пост нет, поэтому я решил поделиться своим решением для тех, кто в нем нуждается.
Таким образом, в основном этот код сканирует все порты любого данного IP-адреса (1000 портов одновременно, то есть 1000 потоков). Я могу сканировать локальный IP-адрес за 2 минуты, интернет-IP немного дольше, может быть, 5. В зависимости от скорости вашего процессора и Интернет-соединение конечно.
Я добавил несколько комментариев для вас, ребята:)
(Пожалуйста, не используйте это в целях взлома xD и Проголосуйте, если вам это нравится)
public partial class PortScanner : Form
{
private int totalScans = 0;
private IPAddress ipAddress;
public PortScanner()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
try
{
//Check for valid IP
if (IPAddress.TryParse(txtIP.Text, out ipAddress))
{
btnScan.Enabled = false;
btnScan.Text = "Scanning...";
//Stops GUI Freeze
MethodInvoker startScanning = new MethodInvoker(ScanPorts);
startScanning.BeginInvoke(null, null);
}
else
{
MessageBox.Show("Invalid IP");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void ScanPorts()
{
int startPort = 1;
int endPoint = 65535;
// n ports to scan!
int maxTheads = 1000;
//Set progressbar
myProgressBar.Value = 0;
myProgressBar.Step = 1;
myProgressBar.Maximum = endPoint - startPort + 1;
//Main task list (consist of multiple lists of 1000 tasks)
List<List<Task>> myTasks = new List<List<Task>>();
for (int i = startPort; i <= endPoint; i = i + maxTheads)
{
List<Task> subTasks = new List<Task>();
for (int j = i; j < i + maxTheads && j <= endPoint; j++)
{
subTasks.Add(ScanSinglePortTask(j));
}
myTasks.Add(subTasks);
}
//Start ALL TASKS
startTask(myTasks);
}
public void startTask(List<List<Task>> myTasks)
{
//A thousand task at a time.
foreach (List<Task> t in myTasks)
{
foreach (Task st in t)
{
st.Start();
}
Task.WaitAll(t.ToArray());
}
btnScan.Enabled = true;
btnScan.Text = "Start Scanning";
}
private Task ScanSinglePortTask(int currPort)
{
return new Task(()=>
{
try
{
using (var tcpportScan = new TcpClient())
{
tcpportScan.SendTimeout = 10;
tcpportScan.Connect(ipAddress, (int)currPort);
}
Response("IP: " + ipAddress.ToString() + " - Port " + currPort + " open.\n");
}
catch (Exception)
{
Response("IP: " + ipAddress.ToString() + " - Port " + currPort + " closed.\n");
}
}, TaskCreationOptions.LongRunning);
}
private void Response(object message)
{
totalScans++;
if (message != null)
{
try
{
lblProgress.Text = "Total portscan: " + totalScans.ToString();
lbConnections.Items.Add(((string)message));
lbConnections.SelectedIndex = lbConnections.Items.Count - 1;
myProgressBar.PerformStep();
if (((string)message).EndsWith("open.\n"))
{
lbOpenConnections.Items.Add((string)message);
}
}
catch (Exception)
{
}
}
}
}
1 ответ
Каждый управляемый поток или волокно в.Net потребляет мегабайт стекового пространства. Если вам не нужно так много места в стеке и вы хотите иметь больше потоков (кстати, не говорите, что это хорошая идея!), Вы можете контролировать размер пространства стека, уменьшив его, что позволит создавать больше потоков
Эта статья поможет вам понять, почему LongRunning оказывает влияние; вы в основном обходите пул потоков и создаете отдельный поток.