利用多线程设计群ping工具
扫描局域网内有哪些可以使用的IP
Ping 的工作原理
Ping 基于 ICMP(Internet 控制报文协议)实现网络连通性检测,工作流程如下:
- 源主机向目标 IP 发送 ICMP Echo 请求报文(Type=8)
- 目标主机收到后,返回 ICMP Echo 应答报文(Type=0)
- 源主机通过是否收到应答及时间差,判断目标是否可达及网络延迟
- 若超时未收到应答或途中 TTL 耗尽,会收到 ICMP 差错报文
C++ 多线程扫描局域网 IP 步骤
步骤 1:准备开发环境
- 需支持 C++11 及以上标准(提供线程库)
- Windows 系统需包含 Windows.h,Linux 系统需包含 netinet/ip_icmp.h 等网络头文件
步骤 2:创建原始套接字
原始套接字用于发送和接收 ICMP 报文,需要管理员 /root 权限
步骤 3:实现 ICMP 报文构造与解析
构造符合 ICMP 规范的 Echo 请求报文,包含类型、代码、校验和、标识符、序列号等字段
步骤 4:实现多线程扫描逻辑
使用线程池并发处理多个 IP 的 Ping 请求,避免线程创建销毁的开销
步骤 5:结果收集与显示
收集各线程返回的扫描结果,统一显示存活的 IP 地址
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <chrono>
#include <winsock2.h>
#include <iphlpapi.h>
#include <icmpapi.h>#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")using namespace std;vector<string> liveIPs;
mutex mtx;// 检查单个IP是否存活
bool pingIP(const char* ipAddress) {HANDLE hIcmpFile;unsigned long ipaddr = inet_addr(ipAddress);if (ipaddr == INADDR_NONE) {return false;}hIcmpFile = IcmpCreateFile();if (hIcmpFile == INVALID_HANDLE_VALUE) {return false;}const int requestSize = 32;char requestData[requestSize] = {0};for (int i = 0; i < requestSize; i++) {requestData[i] = 'a' + i;}char replyBuffer[sizeof(ICMP_ECHO_REPLY) + requestSize];DWORD replySize = sizeof(replyBuffer);DWORD timeout = 1000; // 超时时间1秒DWORD result = IcmpSendEcho(hIcmpFile, ipaddr, requestData, requestSize, NULL, replyBuffer, replySize, timeout);IcmpCloseHandle(hIcmpFile);return (result > 0);
}// 线程工作函数:扫描IP段
void scanIPRange(const string& baseIP, int start, int end) {for (int i = start; i <= end; i++) {string ip = baseIP + "." + to_string(i);if (pingIP(ip.c_str())) {lock_guard<mutex> lock(mtx);liveIPs.push_back(ip);}}
}// 生成IP范围并启动多线程扫描
void scanNetwork(const string& baseIP, int threadCount = 10) {liveIPs.clear();// 计算每个线程负责的IP范围int ipsPerThread = 254 / threadCount;vector<thread> threads;for (int i = 0; i < threadCount; i++) {int start = i * ipsPerThread + 1;int end = (i == threadCount - 1) ? 254 : (i + 1) * ipsPerThread;threads.emplace_back(scanIPRange, baseIP, start, end);}// 等待所有线程完成for (auto& t : threads) {if (t.joinable()) {t.join();}}
}int main() {WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {cerr << "WSA初始化失败" << endl;return 1;}string baseIP;cout << "请输入局域网前缀(如192.168.1): ";cin >> baseIP;cout << "开始扫描局域网..." << endl;auto startTime = chrono::steady_clock::now();// 使用10个线程进行扫描scanNetwork(baseIP, 10);auto endTime = chrono::steady_clock::now();chrono::duration<double> elapsed = endTime - startTime;cout << "\n扫描完成,耗时: " << elapsed.count() << "秒" << endl;cout << "存活的IP地址列表:" << endl;for (const auto& ip : liveIPs) {cout << ip << endl;}WSACleanup();return 0;
}
// 线程参数结构
struct ThreadData
{
CString ip; // IP地址
int thread_id; // 线程ID
BOOL thread_result; // Ping结果(TRUE=在线)
MPingDlg* pDlg; // 对话框指针
HANDLE hEvent;
};