c#执行扫描tcp端口,没有Out of Memory异常

时间:2014-06-04 20:17:46

标签: c# tcp ip port task

所以我试图用给定的IP地址扫描开放端口。 我找到了一些例子,但是如果我给出65535个任务,我会得到Out of Memory异常。 我虽然嗯,也许它很多。所以我尝试了2000 ..还是很多。一千? YES。

但显然问题在于'TaskCreationOptions.LongRunning'。如果我尝试TaskCreationOptions.None是everyhting但真的很慢!!就像我奶奶可以更快地扫描端口一样。

有趣的是,如果我调试(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();
    }

修改

TEMP SOLUTION

所以我设法通过将我的平台目标从x86设置为x64来摆脱Out of Memory异常。

因此,x86具有2Gigs的VIRTUAL内存,而x64则超过6TB + VIRTUAL内存。

如果你问我这不是一个解决方案,而是一个临时问题。

新解决方案

x86和x64位兼容!

我实施的排队系统,这篇文章没有答案,所以我想我会为那些需要它的人分享我的解决方案。

基本上,此代码扫描任何给定IP地址的所有端口(同时1000个端口,因此1000个线程) 我可以在2分钟内扫描一个本地IP,一个互联网IP有点长,可能是5个。取决于你的CPU速度和互联网连接。

我为你们添加了一些评论:)

(请不要将此用于黑客目的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 个答案:

答案 0 :(得分:0)

.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