不多说先看一下运行效果:
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