在區域網路管理或網路工具開發中,快速獲取 LAN 內所有活躍主機的 IP 與主機名稱是常見需求。本文提供一個基於 C# WinForms 的完整範例,採用多執行緒並行掃描 255 個 IP 位址,並透過 DNS 反向解析取得主機名稱,最後在 ListView 與 TextBox 中顯示結果,附帶進度條顯示掃描進度。
Dns.GetHostEntry 反向查詢。string[255,2] 暫存 IP 與主機名,掃描完成後一次性繫結到 UI。private void LanSearch()
{
thread = new Thread[255];
Thread threadProgress = new Thread(new ThreadStart(ProgressSearch));
threadProgress.Start();
string localhost = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString();
string baseIP = localhost.Substring(0, localhost.LastIndexOf('.'));
for (int i = 0; i < 255; i++)
{
int index = i; // 避免閉包捕捉變更
ThreadStart ts = () => LanSearchThreadMethod(index, baseIP);
thread[i] = new Thread(ts);
thread[i].Name = i.ToString();
thread[i].Start();
// 簡易逾時控制:100ms 未完成則中止(實務建議改用 Task 與 CancellationToken)
if (!thread[i].Join(100))
thread[i].Abort();
}
GetLanHost();
ListLanHost();
}
private void LanSearchThreadMethod(int index, string baseIP)
{
try
{
IPAddress scanIP = IPAddress.Parse($"{baseIP}.{index + 1}");
IPHostEntry hostEntry = Dns.GetHostEntry(scanIP);
if (hostEntry != null)
{
LanHost[index, 0] = scanIP.ToString();
LanHost[index, 1] = hostEntry.HostName;
}
}
catch { /* 忽略解析失敗的 IP */ }
}
private void ProgressSearch()
{
for (int i = 0; i < 255; i++)
{
this.Invoke((Action)(() => progressBarSearch.Value = i + 1));
Thread.Sleep(100);
}
}
private void ListLanHost()
{
listView1.View = View.List;
listView1.Items.Clear();
for (int i = 0; i < 255; i++)
{
if (!string.IsNullOrEmpty(LanHost[i, 0]))
{
ListViewItem item = new ListViewItem(LanHost[i, 1]);
item.Tag = LanHost[i, 0];
listView1.Items.Add(item);
}
}
}
Parallel.For 或 Task.WhenAll 可大幅簡化程式碼,並提供更好的取消、異常處理與執行緒池管理。Dns.GetHostEntryAsync,避免阻塞執行緒。SemaphoreSlim 或 ParallelOptions.MaxDegreeOfParallelism 限制並行數(如 50~100)。Interlocked.Increment 計數已完成掃描數,配合 IProgress<T> 更新 UI,取代固定計時器。Invoke,現代寫法可搭配 async/await 與 SynchronizationContext。TextBox (多行)、Button、ProgressBar、ListView (含兩欄 ColumnHeader)。System.Net, System.Threading, System.Windows.Forms。FormClosing 中正確釋放執行緒資源,避免程式關閉時殘留執行緒。本範例展示了傳統 Thread 類別實作 LAN 掃描的基本原理。雖然程式碼可執行,但現代開發強烈建議改用 Task/async-await 模式,配合 Parallel.ForEach 或 SemaphoreSlim 控制並行度,能獲得更佳的效能、穩定度與可維護性。