在C#中使用Threads和ConcurrentBag

时间:2017-12-30 14:01:49

标签: c# multithreading

我正在用C#构建一个简单的端口扫描程序。我已经拥有端口扫描功能,用户传递要使用的线程数以及IP地址范围。所以,我现在所拥有的是我已经解析了范围并创建了一个包含该范围内所有IP地址的ConcurrentBag。我也有一系列线程。所以,它部分看起来像这样:

var ipsInRange = IPAddressRange.Parse(range);

Thread[] hostThreads = new Thread[(int)threads];
ConcurrentBag<IPAddress> ips = new ConcurrentBag<IPAddress>();
foreach (var ip in ipsInRange)
{
    ips.Add(ip);
}

IPAddress address;
while (!ips.IsEmpty)
{
    if (ips.TryTake(out address))
    {
        PortScanner ps = new PortScanner(address);
        ps.Scan();
    }
}

// I want to assign each thread one IP address, create a new PortScanner 
// instance as above, and scan the IP. I want to delete the scanned IPs 
// from the bag. When the thread finishes with scanning, I want to assign 
// a new one to it. I want to continue like this until the bag is empty, 
// i.e. all the IPs are processed.
// So, simply I want to scan multiple IPs at the same time, using the above 
// thread array and the ConcurrentBag containing list of IPs.

尽管如此,我之前没有使用ThreadsConcurrentBag,我想要实现的内容在上面的评论中写到。任何想法如何将上述线程合并到应用程序中?

2 个答案:

答案 0 :(得分:2)

我建议使用Task Parallel Library而不是自己管理线程。它导致代码简短易读,您既不需要处理线程,也不需要处理ConcurrentBag。

如果在端口扫描开始之前知道所有IP地址(即您不需要在端口扫描期间添加/删除IP地址),代码就可以这么简单:

var ipsInRange = IPAddressRange.Parse(range);

var options = new ParallelOptions()
{
    MaxDegreeOfParallelism = 5// Set number of IP addresses to be processed concurrently
};

Parallel.ForEach(
    ipsInRange,
    options,
    (address) => { PortScanner ps = new PortScanner(address); ps.Scan(); });

如果您需要支持在端口扫描正在进行时可以修改IP地址列表(从其他线程)的场景,则需要在BlockingCollection中包装ipsInRange集合,但是你的问题在我看来并不需要。

答案 1 :(得分:1)

我看到了解决方案:

  1. 使用IP地址
  2. 创建blocking collection
  3. 创建几个任务,从coolection中获取IP并扫描它。

    var bc = new BlockingCollection<string>();
    //...
    bc.Add(ip); //add addresses from another thread, or smth else
    //...
    
    for(int i = 0; i < 10; i++)
    {
        Task.Run(()=>
        {
            var address = bc.Take();
            PortScanner ps = new PortScanner(address);
            ps.Scan();
        });
    }
    
  4. 你有10个线程,扫描地址,他们会等待,而集合可以给他们下一个元素。