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 потребляет мегабайт стекового пространства. Если вам не нужно так много места в стеке и вы хотите иметь больше потоков (кстати, не говорите, что это хорошая идея!), Вы можете контролировать размер пространства стека, уменьшив его, что позволит создавать больше потоков

http://www.atalasoft.com/cs/blogs/rickm/archive/2008/04/22/increasing-the-size-of-your-stack-net-memory-management-part-3.aspx

Эта статья поможет вам понять, почему LongRunning оказывает влияние; вы в основном обходите пул потоков и создаете отдельный поток.

http://msdn.microsoft.com/en-us/library/ff963549.aspx

Другие вопросы по тегам