C++ Ping扫描源码

不多说先看一下运行效果:

头文件声明:

FORWARD_DECLARE_STRUCT(IPHeader)
FORWARD_DECLARE_STRUCT(PingReply)
FORWARD_DECLARE_STRUCT(ICMPHeader)

class DoxPing
{

public:

    /* @接口 默认构造函数
     * @邮箱 [email protected]
     * @时间 2018年11月30号
     */
    DoxPing();

    /* @接口 默认析构函数
     * @邮箱 [email protected]
     * @时间 2018年11月30号
     */
    ~DoxPing();
    
    /* @接口 扫描主机根据指定的ip地址
     * @返回 bool 成功返回值为true,否则返回值为false
     * @邮箱 [email protected]
     * @时间 2018年11月30号
     */
    virtual bool ping(ulong, ulong dwTimeout = 128);
    
    /* @接口 扫描多个主机根据指定的ip地址段
     * @返回 bool 成功返回值为true,否则返回值为false
     * @邮箱 [email protected]
     * @时间 2018年12月12号
     */
    virtual bool pings(ulong, ulong, ulong dwTimeout = 128);

    /* @接口 扫描主机根据指定的ip地址
     * @返回 bool 成功返回值为true,否则返回值为false
     * @邮箱 [email protected]
     * @时间 2018年11月30号
     */
    virtual bool ping(const QString &, ulong dwTimeout = 128);
    
    /* @接口 扫描多个主机根据指定的ip地址段
     * @返回 bool 成功返回值为true,否则返回值为false
     * @邮箱 [email protected]
     * @时间 2018年11月30号
     */
    virtual BoolArr pings(const ULongArr &, ulong dwTimeout = 128);

    /* @接口 扫描多个主机根据指定的ip地址段
     * @返回 bool 成功返回值为true,否则返回值为false
     * @邮箱 [email protected]
     * @时间 2018年11月30号
     */
    virtual BoolArr pings(const QStringList &, ulong dwTimeout = 128);

public:

    /* @接口 创建扫描的线程
     * @邮箱 [email protected]
     * @时间 2018年12月18号
     */
    static ulong createPingThread(void *);

private:

    /* @接口 构建ICMP数据包
     * @返回 bool 成功返回值为true,否则返回值为false
     * @邮箱 [email protected]
     * @时间 2018年12月2号
     */
    void buildICMP();

    /* @接口 
     * @返回 bool 成功返回值为true,否则返回值为false
     * @邮箱 [email protected]
     * @时间 2018年11月30号
     */
    ulong GetTickCountCalibrate();

    /* @接口 计算检验和
     * @返回 bool 成功返回值为true,否则返回值为false
     * @邮箱 [email protected]
     * @时间 2018年11月30号
     */
    ushort CalCheckSum(ushort *, int);

    /* @接口 发送ICMP数据包
     * @返回 bool 成功返回值为true,否则返回值为false
     * @作者 杨发荷
     * @邮箱 [email protected]qq.com
     * @时间 2018年12月2号
     */
    bool sendToICMP(const sockaddr_in &);

    /* @接口 配置SOCKET
     * @参数 ulong IP地址
     * @参数 sockaddr_in 
     * @邮箱 [email protected]
     * @时间 2018年12月2号
     */
    void buildSocket(ulong, sockaddr_in &);

    /* @接口 
     * @邮箱 [email protected]
     * @时间 2018年11月30号
     */
    bool pingCore(ulong, PingReply *, ulong);

    /* @接口
     * @返回 bool 成功返回值为true,否则返回值为false
     * @邮箱 [email protected]
     * @时间 2018年12月2号
     */
    bool recvFromICMP(sockaddr_in &, PingReply *);

    /* @接口
     * @邮箱 [email protected]
     * @时间 2018年11月30号
     */
    bool Ping(ulong, PingReply *pPingReply = NULL, ulong dwTimeout = 128);

    /* @接口
     * @邮箱 [email protected]om
     * @时间 2018年11月30号
     */
    bool Ping(char *, PingReply *pPingReply = NULL, ulong dwTimeout = 128);

public:

    HANDLE m_event;
    ushort m_usSeq;
    ulong m_sockRaw;
    char *m_szICMPData;
    bool m_bIsInitSucc;
    ulong m_ulSendTimestamp;
    ushort m_usCurrentProcID;
    static ulong g_usPacketSeq;

};

源文件定义:


ulong DoxPing::g_usPacketSeq = 0;

DoxPing::DoxPing()
    : m_szICMPData(NULL)
    , m_bIsInitSucc(FALSE)
    , m_ulSendTimestamp(0)
{
    WSADATA WSAData;
    WSAStartup(MAKEWORD(1, 1), &WSAData);
    m_event = WSACreateEvent();
    m_usCurrentProcID = (ushort)GetCurrentThreadId();
    if((m_sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, 0)) != SOCKET_ERROR)
    {
        WSAEventSelect(m_sockRaw, (WSAEVENT)m_event, FD_READ);
        m_bIsInitSucc = TRUE;
        int sz = DEF_PACKET_SIZE + sizeof(ICMPHeader);
        m_szICMPData = new char[sz];
        memset(m_szICMPData, 0, sz);
        if(m_szICMPData == NULL)
            m_bIsInitSucc = FALSE;
    }
}

DoxPing::~DoxPing()
{
    closesocket(m_sockRaw);
    WSACleanup();
    if(NULL != m_szICMPData)
    {
        delete[]m_szICMPData;
        m_szICMPData = NULL;
    }
    CloseHandle(m_event);
}

void DoxPing::buildICMP()
{
    int nICMPDataSize = DEF_PACKET_SIZE + sizeof(ICMPHeader);
    m_ulSendTimestamp = GetTickCountCalibrate();
    m_usSeq = ++g_usPacketSeq;
    memset(m_szICMPData, 0, nICMPDataSize);
    ICMPHeader *pICMPHeader = (ICMPHeader*)m_szICMPData;
    pICMPHeader->m_byType = ECHO_REQUEST;
    pICMPHeader->m_byCode = 0;
    pICMPHeader->m_usID = m_usCurrentProcID;
    pICMPHeader->m_usSeq = m_usSeq;
    pICMPHeader->m_ulTimeStamp = m_ulSendTimestamp;
    pICMPHeader->m_usChecksum = CalCheckSum((USHORT*)m_szICMPData, nICMPDataSize);
}

ULONG DoxPing::GetTickCountCalibrate()
{
    static ULONG s_ulFirstCallTick = 0;
    static LONGLONG s_ullFirstCallTickMS = 0;
    SYSTEMTIME systemtime;
    FILETIME filetime;
    GetLocalTime(&systemtime);
    SystemTimeToFileTime(&systemtime, &filetime);
    LARGE_INTEGER liCurrentTime;
    liCurrentTime.HighPart = filetime.dwHighDateTime;
    liCurrentTime.LowPart = filetime.dwLowDateTime;
    LONGLONG llCurrentTimeMS = liCurrentTime.QuadPart / 10000;
    if(s_ulFirstCallTick == 0)
        s_ulFirstCallTick = GetTickCount();
    if(s_ullFirstCallTickMS == 0)
        s_ullFirstCallTickMS = llCurrentTimeMS;
    return s_ulFirstCallTick + (ULONG)(llCurrentTimeMS - s_ullFirstCallTickMS);
    return 0;
}

ulong DoxPing::createPingThread(void *param)
{
    return 0;
}

bool DoxPing::ping(ulong dwDestIP, ulong dwTimeout)
{
    PingReply pingReply;
    return pingCore(dwDestIP, &pingReply, dwTimeout);
}

void DoxPing::buildSocket(ulong ip, sockaddr_in &addr)
{
    addr.sin_port = htons(0);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = ip;
}

bool DoxPing::ping(const QString &ip, ulong dwTimeout)
{
    char *IP = ip.toLocal8Bit().data();
    PingReply pingReply;
    return Ping(IP, &pingReply, dwTimeout);
}

ushort DoxPing::CalCheckSum(ushort *pBuffer, int nSize)
{
    unsigned long ulCheckSum = 0;
    while(nSize > 1)
    {
        ulCheckSum += *pBuffer++;
        nSize -= sizeof(USHORT);
    }
    if(nSize)
        ulCheckSum += *(UCHAR*)pBuffer;
    ulCheckSum = (ulCheckSum >> 16) + (ulCheckSum & 0xffff);
    ulCheckSum += (ulCheckSum >> 16);
    return (USHORT)(~ulCheckSum);
}

bool DoxPing::sendToICMP(const sockaddr_in &sockAddrDest)
{
    int nSockaddrDestSize = sizeof(sockAddrDest);
    int nICMPDataSize = DEF_PACKET_SIZE + sizeof(ICMPHeader);
    return sendto(m_sockRaw, m_szICMPData, nICMPDataSize, 0, (struct sockaddr*)&sockAddrDest, nSockaddrDestSize) != SOCKET_ERROR;
}

bool DoxPing::pings(ulong sip, ulong eip, ulong dwTimeOut)
{
    int count = eip - sip;

    //CreateThread(NULL, 0, )
    //CreateThread()
    return false;
}

BoolArr DoxPing::pings(const QStringList &ips, ulong dwTimeout)
{
    QList<bool> flags;
    for(int idx = 0; idx < ips.length(); ++idx)
        flags.append(ping(ips[idx], dwTimeout));
    return flags;
}

BoolArr DoxPing::pings(const ULongArr &dwDestIPs, ulong dwTimeout)
{
    BoolArr flags;
    for(int idx = 0; idx < dwDestIPs.length(); ++idx)
        flags.append(ping(dwDestIPs[idx], dwTimeout));
    return flags;
}

bool DoxPing::Ping(ulong dwDestIP, PingReply *pPingReply, ulong dwTimeout)
{
    return pingCore(dwDestIP, pPingReply, dwTimeout);
}

bool DoxPing::Ping(char *szDestIP, PingReply *pPingReply, ulong dwTimeout)
{
    if(NULL != szDestIP)
        return pingCore(inet_addr(szDestIP), pPingReply, dwTimeout);
    return false;
}

bool DoxPing::pingCore(ulong dwDestIP, PingReply *pPingReply, ulong dwTimeout)
{
    if(!m_bIsInitSucc) return false;
    sockaddr_in sockAddrDest;
    buildSocket(dwDestIP, sockAddrDest);
    //构建ICMP包
    buildICMP();
    //发送ICMP报文
    if(!sendToICMP(sockAddrDest)) return false;
    //判断是否需要接收相应报文
    if(pPingReply == NULL) return true;
    while(TRUE)
    {
        if(WSAWaitForMultipleEvents(1, &m_event, FALSE, dwTimeout, FALSE) == WSA_WAIT_TIMEOUT) return false;
        //接收响应报文
        if(recvFromICMP(sockAddrDest, pPingReply)) return true;
        //超时
        if(GetTickCountCalibrate() - m_ulSendTimestamp >= dwTimeout) return false;
    }
    return false;
}

bool DoxPing::recvFromICMP(sockaddr_in &sockAddrDest, PingReply *pPingReply)
{
    WSANETWORKEVENTS netEvent; WSAEnumNetworkEvents(m_sockRaw, m_event, &netEvent);
    if(netEvent.lNetworkEvents & FD_READ)
    {
        char recvbuf[256] = { "\0" };
        int nSockaddrDestSize = sizeof(sockAddrDest);
        ULONG nRecvTimestamp = GetTickCountCalibrate();
        int nPacketSize = recvfrom(m_sockRaw, recvbuf, 256, 0, (struct sockaddr*)&sockAddrDest, &nSockaddrDestSize);
        if(nPacketSize == SOCKET_ERROR) return false;
        IPHeader *pIPHeader = (IPHeader*)recvbuf;
        ushort usIPHeaderLen = (ushort)((pIPHeader->m_byVerHLen & 0x0f) * 4);
        ICMPHeader *pICMPHeader = (ICMPHeader *)(recvbuf + usIPHeaderLen);
        if(pICMPHeader->m_usID == m_usCurrentProcID //是当前进程发出的报文
            && pICMPHeader->m_byType == ECHO_REPLY //是ICMP响应报文
            && pICMPHeader->m_usSeq == m_usSeq //是本次请求报文的响应报文
            )
        {
            pPingReply->m_usSeq = m_usSeq;
            pPingReply->m_dwRoundTripTime = nRecvTimestamp - pICMPHeader->m_ulTimeStamp;
            pPingReply->m_dwBytes = nPacketSize - usIPHeaderLen - sizeof(ICMPHeader);
            pPingReply->m_dwTTL = pIPHeader->m_byTTL;
            return true;
        }
    }
    return false; //有可能还没有收到
}

源程序下载地址:

示例程序运行方式:https://blog.csdn.net/yangfahe1/article/details/84028318