简单写了一个局域网探测工具。

前言

因为公司设备太多,偶尔遇到 IP 分配冲突问题,所以写了一个可视化的 GUI 小工具来快速排查掉已被占用的 IP 地址以及分析局域网概况,包括局域网主机延迟、在线状态、系统类型、主机名、Mac地址等。

成品展示

下载软件

文图介绍

通过设置要扫描的局域网 IP 段和起始结束数值即可开始扫描。

LanTest1

扫描后可以查看结果信息。

LanTest2

通过详细模式可以查看更多细节,以及分析局域网概况,包括局域网主机延迟、在线状态、系统类型、主机名、Mac地址等。

LanTest3

功能设想与实现

基础检测方案:
通过基础 Ping 功能对目标 IP 发出 ICMP 数据,以取得目标 IP 状态(是否在线、延迟)。

性能优化方案:
使用多线程+线程池方式调用检测,减小等待时间,提升运行效率。

代码逻辑

通过 C# 自带的 Net 实现基础 Ping 服务

1
2
Ping ping = new Ping();
PingReply reply = ping.Send(ipAddress);

Ping 发送后,获取目标的状态信息。

1
2
3
4
5
// 获取状态
reply.Status

// 获取延迟
reply.RoundtripTime

至此一个基础的探测逻辑成功实现。

代码书写:

先创建一个实体类,用来存放状态信息。

1
2
3
4
5
6
7
8
internal class StatusEntity
{
public string IPAddress { get; set; }

public bool IsOnline { get; set; }

public long Ms { get; set; }
}

现在要结合多线程与遍历设置的局域网 IP 范围进行获取遍历后的状态信息结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
int startRange = 1; //IPv4 第四段开始地址
int endRange = 255; //IPv4 第四段结束地址

for (int i = startRange; i <= endRange; i++)
{
string ipAddress = baseIpAddress + i.ToString();
Trace.WriteLine($"{ipAddress} | {baseIpAddress + i.ToString()}");
Thread thread = new Thread(() => PingHost(ipAddress));
thread.Start();
}

// 设置一个线程池用于等待所有线程退出事件。
ThreadPool.QueueUserWorkItem(_ => WaitPingTestAllThreads());

PingHost() 为自封装方法,通过调用 PingHost(传入 IP 地址),然后将 Ping 结果存入 List 内。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private BlockingCollection<StatusEntity> statusEntities = new BlockingCollection<StatusEntity>();

void PingHost(string ipAddress)
{
try
{
Ping ping = new Ping();
PingReply reply = ping.Send(ipAddress);

// 添加 Ping 结果信息到列表保存。
statusEntities.Add(new StatusEntity { IPAddress = ipAddress, IsOnline = reply.Status == IPStatus.Success, Ms = reply.RoundtripTime });
}
catch (Exception ex)
{
Trace.WriteLine($"{ipAddress}: 请求错误,错误信息:{ex.Message}");
}
}

将结果渲染成 UI 展示给用户。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 所有线程结束后,渲染 UI。
private void WaitPingTestAllThreads()
{
foreach (StatusEntity statusEntity in statusEntities)
{
this.Invoke(new Action(() =>
{
Panel panel = new Panel();
panel.Width = 48;
panel.Height = 48;

//显示 IP 标签
Label num = new Label();
num.AutoSize = false;
num.Margin = new Padding(0);
num.Width = width;
num.Text = statusEntity.IPAddress

// 显示 延迟 标签
Label ms = new Label();
ms.AutoSize = false;
ms.Margin = new Padding(0);
ms.Width = width;
ms.Text = statusEntity.Ms

panel.Controls.Add(num);
panel.Controls.Add(ms);

//将控件加入到主控件内。
Panel_Main.Controls.Add(panel);
}));
}
}

后续更新方向

  • 有些时候 Ping 可能也不能准确获取状态,比如防火墙拦截之类的。需要多个方案配合会更稳定。
  • 增加更详细的 UI 状态显示。