多线程IP地址扫描
窗体展示

代码参考
//From:TengMMVP
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Net;
using System.Threading;
using System.Windows.Forms;
namespace IPAdressForm
{
public partial class MainForm : Form
{
public MainForm()
{
//初始化窗体
InitializeComponent();
//默认隐藏提示标签
label_Tip.Visible = false;
}
//鼠标事件:“单线程”按钮被点击
private void button_SingleThread_Click(object sender, EventArgs e)
{
//如果“单线程”按钮被点击,调用启动扫描函数,传参“false”
RunScan(isMultithreaded: false);
}
//鼠标事件:“多线程”按钮被点击
private void button_MultiThread_Click(object sender, EventArgs e)
{
//如果“多线程”按钮被点击,调用启动扫描函数,传参“true”
RunScan(isMultithreaded: true);
}
//启动扫描函数:首先进行扫描前的预处理,然后根据参数调用具体的扫描函数进行扫描
private void RunScan(bool isMultithreaded)
{
//创建了一个新线程来执行扫描操作
new Thread(() =>
{
//使用 `Invoke` 方法在主线程上执行清除 `textBox_Show` 的内容
Action clearAction = () => textBox_Show.Clear();
Invoke(clearAction);
//扫描预处理一:IP地址前缀合法性检查
string ipPrefix = textBox_IPAdressPre.Text;
if (!IsValidIpPrefix(ipPrefix))
{
ShowTip("IP地址前缀不合法。");
return;
}
//扫描预处理二:起始值/终止值合法性检查。
if (!int.TryParse(textBox_Start.Text, out int start) || !int.TryParse(textBox_End.Text, out int end) || start < 0 || end < start || start > 255 || end > 255)
{
ShowTip("起始或终止值不合法。");
return;
}
Action HideAction = () => label_Tip.Visible = false;
Invoke(HideAction);
//创建一个停表并启动,用于记录总扫描时间
Stopwatch totalStopwatch = new Stopwatch();
totalStopwatch.Start();
if (isMultithreaded)//如果是多线程则运行下面的代码段
{
// 创建一个Thread类型的列表threads,用于存储线程
List<Thread> threads = new List<Thread>();
for (int i = start; i <= end; i++)
{
// 将ipPrefix字符串与循环变量i拼接,构造出IP地址
string ip = ipPrefix + i;
// 创建一个新线程,线程的工作是调用ScanIp方法并传入构造的IP地址
Thread thread = new Thread(() => ScanIp(ip));
threads.Add(thread);
// 启动新创建的线程
thread.Start();
}
// 遍历threads列表中的每个线程
foreach (Thread thread in threads)
{
//调用Join方法,等待当前遍历到的线程执行完毕
thread.Join();
}
}
else//如果是单线程则运行下面的代码段
{
for (int i = start; i <= end; i++)
{
string ip = ipPrefix + i;
// 在单线程模式下直接顺序执行
ScanIp(ip);
}
}
//扫描完毕,停表计时结束
totalStopwatch.Stop();
//使用 `Invoke` 方法在主线程上更新 `textBox_Show`,显示总扫描时间
Invoke((MethodInvoker)delegate
{
textBox_Show.AppendText($"总扫描时间:{totalStopwatch.ElapsedMilliseconds}毫秒\n");
});
})
{ IsBackground = true }.Start();//设置为后台进程并启动
}
//初步判断输入的IP地址前缀是否合法的具体实现
private bool IsValidIpPrefix(string ipPrefix)
{
//采用正则表达式来判断
return System.Text.RegularExpressions.Regex.IsMatch(ipPrefix, @"^(\d{1,3}\.){3}$");
}
//IP扫描的具体实现
private void ScanIp(string ip)
{
Stopwatch stopwatch = Stopwatch.StartNew();
string result;
try
{
IPHostEntry hostEntry = Dns.GetHostEntry(ip);
stopwatch.Stop();
result = $"扫描地址:{ip},扫描用时:{stopwatch.ElapsedMilliseconds}毫秒,主机DNS名称:{hostEntry.HostName}\r\n";
}
catch
{
stopwatch.Stop();
result = $"扫描地址:{ip},扫描用时:{stopwatch.ElapsedMilliseconds}毫秒,异常:查询不到主机\r\n";
}
//更新界面结果
Invoke((MethodInvoker)delegate { UpdateUI(result); });
}
//更新UI界面的具体实现
private void UpdateUI(string text)
{
// 检查textBox_Show控件的InvokeRequired属性
// 如果为true,说明当前线程不是创建textBox_Show的线程(通常是UI线程)
// 因此需要使用Invoke方法来在UI线程上执行更新操作
if (textBox_Show.InvokeRequired)
{
// 使用Lambda表达式创建一个无参数的Action委托
// 该委托调用textBox_Show的AppendText方法来追加文本
// 然后通过Invoke方法在UI线程上执行这个委托
textBox_Show.Invoke(new Action(() => textBox_Show.AppendText(text)));
}
else
{
// 如果当前线程就是UI线程,则直接调用AppendText方法来追加文本
textBox_Show.AppendText(text);
}
}
//提示标签处理
private void ShowTip(string message)
{
if (label_Tip.InvokeRequired)
{
label_Tip.Invoke(new Action(() =>
{
label_Tip.Text = message;
label_Tip.BackColor = Color.Red;
label_Tip.Visible = true;
}));
}
else
{
label_Tip.Text = message;
label_Tip.BackColor = Color.Red;
label_Tip.Visible = true;
}
}
}
}
//From:TengMMVP