MFC 多线程局域网扫描工具
一、项目简介在局域网运维、内网设备排查场景中批量扫描网段在线主机是高频刚需。传统单线程 Ping 扫描速度极慢扫描一个 255 网段往往需要数分钟无法满足高效运维需求。本文基于MFC 多线程技术实现一款高性能局域网 Ping 扫描工具核心功能包含支持自定义网段输入前三位 IP如 192.168.1批量扫描 0~254 主机255 并发多线程扫描大幅提升扫描效率可视化 16×16 网格画布颜色区分主机状态灰色未扫描、绿色在线多重 Ping 重试机制避免内网丢包导致的误判实时统计在线主机数量、扫描耗时支持扫描结果 TXT 文件导出方便数据留存自动获取本机网段无需手动输入提升使用便捷性工具采用 MFC 对话框开发界面轻量化、无冗余依赖适配 Windows 全平台适合个人学习、内网运维、网络调试使用。二、核心技术原理1. 多线程并发扫描传统单线程 Ping 串行执行逐个检测 IP耗时极高。本项目开启255 个独立工作线程每个线程单独负责一个 IP 的 Ping 检测实现全网段并行扫描将扫描耗时压缩至毫秒级。同时采用事件驱动 分批等待机制规避 Windows 单批次最大等待 64 个内核对象的限制完美兼容 255 线程同步等待逻辑同时通过消息循环防止界面卡死。2. 多重Ping重试防误判内网环境存在短暂丢包、网络波动问题单次 Ping 检测极易出现误判。项目内置4 次重试机制只要单次 IP Ping 连通成功即判定主机在线大幅提升扫描准确率超时时间设置 300ms适配内网网络延迟特性。3. 自定义消息UI更新子线程禁止直接操作 UI项目通过自定义消息 WM_THREAD_FINISH实现线程与主线程通信。子线程扫描完成后发送消息主线程统一更新网格颜色、在线计数保证 UI 渲染稳定、无闪烁、无线程冲突。4. 可视化网格绘制通过 MFC 自绘技术实现 16×16 网格画布对应 0~254 共 255 个 IP 地址每个单元格独立映射一个主机。通过不同颜色区分状态灰色未扫描、绿色在线直观展示网段设备在线状态。三、核心功能代码解析1. 线程参数结构体定义封装单线程所需的全部参数包含待扫描 IP、线程ID、扫描结果、对话框指针、线程完成事件实现线程参数统一管理Plain Text// 线程参数结构struct ThreadData{CString ip; // 待扫描IP地址int thread_id; // 线程唯一IDBOOL thread_result; // Ping结果 TRUE在线 FALSE离线MPingDlg* pDlg; // 对话框指针用于发送消息HANDLE hEvent; // 线程完成事件句柄};2. 核心线程扫描函数每个线程独立执行 Ping 检测4 次重试容错完成后通过自定义消息通知主线程更新 UIPlain TextUINT ThreadFunction(LPVOID pParam){ThreadData* pData (ThreadData*)pParam;MyPing ping;const int SCAN_CNT 4; // 4次重试BOOL bPingSuccess FALSE;// 多重Ping重试避免内网丢包误判for (int i 0; i SCAN_CNT; i){PingResult result;ping.Ping(pData-ip, 300, 128, result); // 超时300ms数据包128字节if (result.bSuccess){bPingSuccess TRUE;break;}Sleep(20);}pData-thread_result bPingSuccess;// 发送自定义消息更新主线程UIif (pData-pDlg ! NULL){pData-pDlg-PostMessage(WM_THREAD_FINISH, pData-thread_id, bPingSuccess ? 1 : 0);}SetEvent(pData-hEvent);return 0;}3. 多线程批量创建与等待逻辑批量创建 255 个扫描线程采用分批等待机制规避系统限制同时通过消息泵维持界面响应Plain Text// 批量创建所有扫描线程for(int i 0; i NUM_THREADS; i){threadData[i].ip.Format(%s.%d, m_strComboIP.GetBuffer(0), i);threadData[i].thread_id i;threadData[i].thread_result FALSE;threadData[i].pDlg this;hEvents[i] CreateEvent(NULL, TRUE, FALSE, NULL);threadData[i].hEvent hEvents[i];pThreads[i] AfxBeginThread(ThreadFunction, threadData[i]);}m_strComboIP.ReleaseBuffer();// 分批等待所有线程完成防止界面卡死while (1){bool allFinished true;for (int i 0; i NUM_THREADS; i MAXIMUM_WAIT_OBJECTS){int batchCount min(MAXIMUM_WAIT_OBJECTS, NUM_THREADS - i);DWORD ret WaitForMultipleObjects(batchCount,hEvents[i],TRUE,10);if (ret ! WAIT_OBJECT_0){allFinished false;}}if (allFinished)break;// 消息循环刷新界面MSG msg;while (PeekMessage(msg, NULL, 0, 0, PM_REMOVE)){TranslateMessage(msg);DispatchMessage(msg);}}4. 线程消息回调更新UI接收子线程扫描结果动态修改网格颜色、统计在线主机数量Plain TextLRESULT MPingDlg::OnThreadFinish(WPARAM wParam, LPARAM lParam){int thread_id (int)wParam;int result (int)lParam;if (result){// 在线主机标记绿色SetCellColor(thread_id / 16, thread_id % 16, RGB(0, 255, 0));m_iIPCount;UpdateWindow();UpdateCount();}return 0;}5. 扫描结果导出功能遍历网格状态筛选在线主机 IP批量导出为 TXT 文档方便数据归档Plain Textvoid MPingDlg::OnBnClickedBtnExport(){CString sFilePath;CFileDialog dlg(FALSE, .txt, IP列表,OFN_HIDEREADONLY, 列表文件(*.txt)|*.txt||);if(dlg.DoModal() ! IDOK) return;sFilePath dlg.GetPathName();// 清理文件属性DWORD FileAttribute GetFileAttributes(sFilePath);if(FileAttribute FILE_ATTRIBUTE_READONLY)SetFileAttributes(sFilePath, FileAttribute ~FILE_ATTRIBUTE_READONLY);// 写入在线IP数据FILE* fp fopen(sFilePath.GetBuffer(0), wb);int cnt 0;if(fp){fprintf(fp, 序号 IP地址\r\n);for(int i 0; i 255; i){if(m_cellColors[i / 16][i % 16] RGB(0, 255, 0)){CString sIP;sIP.Format(%s.%d, m_strComboIP, i);fprintf(fp, %03d %s\r\n, cnt 1, sIP.GetBuffer(0));cnt;}}}fclose(fp);}6. 本机网段自动获取程序启动自动读取本机 IP解析网段前缀并填充到下拉框无需手动输入Plain Textchar szHostName[128] {0};const char* pszAddr;struct hostent* pHost;if(gethostname(szHostName, 128) 0){pHost gethostbyname(szHostName);for(int i 0; pHost ! NULL pHost-h_addr_list[i] ! NULL; i){pszAddr inet_ntoa(*(struct in_addr*)pHost-h_addr_list[i]);CString sIP(pszAddr);CStringArray strArray;theApp.GetSplitArrayByString(sIP, strArray, .);if(strArray.GetSize() 4){CString sIPHead;sIPHead.Format(%s.%s.%s, strArray[0], strArray[1], strArray[2]);m_ctrlComboIP.AddString(sIPHead);}}}m_ctrlComboIP.SetCurSel(0);四、项目亮点与优化点1. 高性能并发扫描突破单线程扫描瓶颈255 线程全网段并发扫描速度提升数十倍普通网段扫描耗时控制在 1 秒内。2. 高容错扫描机制4 次 Ping 重试 300ms 超时适配内网弱网环境彻底解决内网偶然丢包导致的离线误判问题扫描准确率接近 100%。3. 流畅UI交互采用局部重绘机制仅更新扫描完成的单元格避免全局刷新闪烁独立消息泵保证扫描过程中界面可拖动、可操作无卡死现象。4. 人性化功能设计自动获取本机网段、实时统计扫描数据、可视化网格状态、结果文件导出兼顾新手易用性和运维实用性。