利用多线程设计群ping工具

扫描局域网内有哪些可以使用的IP

Ping 的工作原理

Ping 基于 ICMP(Internet 控制报文协议)实现网络连通性检测,工作流程如下:

  1. 源主机向目标 IP 发送 ICMP Echo 请求报文(Type=8)
  2. 目标主机收到后,返回 ICMP Echo 应答报文(Type=0)
  3. 源主机通过是否收到应答及时间差,判断目标是否可达及网络延迟
  4. 若超时未收到应答或途中 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;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C++ 老炮儿的技术栈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值