MFC之Ping类

网上找的两个pingIP地址的类A和B



A.h

#include <IPHlpApi.h>
#pragma comment(lib, "iphlpapi.lib")

class CPing
{
public:
	CPing(void);
	~CPing(void);
private:
	HINSTANCE hIcmp;
	typedef HANDLE(WINAPI *PIcmpCreateFile)(VOID);
	typedef DWORD(WINAPI *PIcmpSendEcho)(HANDLE, IPAddr, LPVOID, WORD, PIP_OPTION_INFORMATION, LPVOID, DWORD, DWORD);
	typedef BOOL(WINAPI *PIcmpCloseHandle)(HANDLE);
	PIcmpCreateFile        pIcmpCreateFile;
	PIcmpSendEcho        pIcmpSendEcho;
	PIcmpCloseHandle    pIcmpCloseHandle;
public:
	//功能:ping某个地址或者Ip,返回结果
	//参数:v_pszDesAddress-目标域名或者IP
	//参数:v_usTimes-需要ping的次数
	//参数:v_ulTimeout-超时时间,单位毫秒
	//返回值:-1-发生异常,其他大于等于0的值表示未超时的次数
	int Ping(const char *v_pszDesAdress, USHORT v_usTimes, ULONG v_ulTimeout);
};


A.cpp

#include "StdAfx.h"
#include ".\ping.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

//构造函数
CPing::CPing(void)
{
	hIcmp = LoadLibrary("icmp.dll");
	if (NULL != hIcmp)
	{
		pIcmpCreateFile = (PIcmpCreateFile)GetProcAddress(hIcmp, "IcmpCreateFile");
		pIcmpSendEcho = (PIcmpSendEcho)GetProcAddress(hIcmp, "IcmpSendEcho");
		pIcmpCloseHandle = (PIcmpCloseHandle)GetProcAddress(hIcmp, "IcmpCloseHandle");
	}
}
//析构函数
CPing::~CPing(void)
{
	FreeLibrary(hIcmp);
}
//功能:ping某个地址或者Ip,返回结果
//参数:v_pszDesAddress-目标域名或者IP
//参数:v_usTimes-需要ping的次数
//参数:v_ulTimeout-超时时间,单位毫秒
//返回值:-1-发生异常,其他大于等于0的值表示未超时的次数
int CPing::Ping(const char *v_pszDesAdress, USHORT v_usTimes, ULONG v_ulTimeout)
{
	ULONG ulDesIP = 0;
	int ret = 0;

	// 当传递的参数为域名时,解析该域名的IP
	ulDesIP = inet_addr(v_pszDesAdress);
	//域名
	if (ulDesIP == INADDR_NONE)
	{
		// 解析传入域名的IP
		PHOSTENT pHostent = gethostbyname(v_pszDesAdress);
		if (pHostent == NULL)
		{
			return -1;
		}
		ulDesIP = *(DWORD *)pHostent->h_addr;
	}

	// 申请发送缓冲区
	void *sendBuffer = new char[32];
	if (sendBuffer == NULL)
	{
		return -1;
	}

	// 申请接收缓冲区
	unsigned long replySize = sizeof(ICMP_ECHO_REPLY)+32;
	void *replyBuffer = new char[replySize];
	if (replyBuffer == NULL)
	{
		delete[] sendBuffer;
		sendBuffer = NULL;
		return -1;
	}
	PICMP_ECHO_REPLY pIcmpEchoReply = (PICMP_ECHO_REPLY)replyBuffer;

	// 获取ICMP echo所需句柄
	HANDLE hIcmpFile = pIcmpCreateFile();
	if (hIcmpFile == INVALID_HANDLE_VALUE)
	{
		delete[] sendBuffer;
		sendBuffer = NULL;
		delete[] replyBuffer;
		replyBuffer = NULL;
		return -1;
	}

	// 调用IcmpSendEcho,获取Ping值
	for (int i = 0; i<v_usTimes; i++)
	{
		pIcmpSendEcho(hIcmpFile, ulDesIP, sendBuffer, 32, NULL, replyBuffer, replySize, v_ulTimeout);

		if (pIcmpEchoReply->Status == 0)    // 未超时
		{
			ret++;
		}
	}

	//释放缓冲区,关闭句柄
	delete[] replyBuffer;
	delete[] sendBuffer;
	pIcmpCloseHandle(hIcmpFile);

	return ret;
}


B.h

#pragma once  


//这里需要导入库 Ws2_32.lib,在不同的IDE下可能不太一样   
#include <WinSock2.h>  
#pragma comment(lib, "Ws2_32.lib")  

#define DEF_PACKET_SIZE 32  
#define ECHO_REQUEST 8  
#define ECHO_REPLY 0  

struct IPHeader
{
	BYTE m_byVerHLen; //4位版本+4位首部长度  
	BYTE m_byTOS; //服务类型  
	USHORT m_usTotalLen; //总长度  
	USHORT m_usID; //标识  
	USHORT m_usFlagFragOffset; //3位标志+13位片偏移  
	BYTE m_byTTL; //TTL  
	BYTE m_byProtocol; //协议  
	USHORT m_usHChecksum; //首部检验和  
	ULONG m_ulSrcIP; //源IP地址  
	ULONG m_ulDestIP; //目的IP地址  
};

struct ICMPHeader
{
	BYTE m_byType; //类型  
	BYTE m_byCode; //代码  
	USHORT m_usChecksum; //检验和   
	USHORT m_usID; //标识符  
	USHORT m_usSeq; //序号  
	ULONG m_ulTimeStamp; //时间戳(非标准ICMP头部)  
};

struct PingReply
{
	USHORT m_usSeq;
	DWORD m_dwRoundTripTime;
	DWORD m_dwBytes;
	DWORD m_dwTTL;
};

class CPing
{
public:
	CPing();
	~CPing();
	BOOL Ping(DWORD dwDestIP, PingReply *pPingReply = NULL, DWORD dwTimeout = 2000);
	BOOL Ping(char *szDestIP, PingReply *pPingReply = NULL, DWORD dwTimeout = 2000);
private:
	BOOL PingCore(DWORD dwDestIP, PingReply *pPingReply, DWORD dwTimeout);
	USHORT CalCheckSum(USHORT *pBuffer, int nSize);
	ULONG GetTickCountCalibrate();
private:
	SOCKET m_sockRaw;
	WSAEVENT m_event;
	USHORT m_usCurrentProcID;
	char *m_szICMPData;
	BOOL m_bIsInitSucc;
private:
	static USHORT s_usPacketSeq;
};


B.cpp

#include "stdafx.h"  
#include "Ping.h"  

USHORT CPing::s_usPacketSeq = 0;

CPing::CPing() :
m_szICMPData(NULL),
m_bIsInitSucc(FALSE)
{
	WSADATA WSAData;
	WSAStartup(MAKEWORD(1, 1), &WSAData);

	m_event = WSACreateEvent();
	m_usCurrentProcID = (USHORT)GetCurrentProcessId();

	if ((m_sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, 0)) != SOCKET_ERROR)
	{
		WSAEventSelect(m_sockRaw, 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;
		}
	}
}

CPing::~CPing()
{
	WSACleanup();

	if (NULL != m_szICMPData)
	{
		delete[]m_szICMPData;
		m_szICMPData = NULL;
	}
}

BOOL CPing::Ping(DWORD dwDestIP, PingReply *pPingReply, DWORD dwTimeout)
{
	return PingCore(dwDestIP, pPingReply, dwTimeout);
}

BOOL CPing::Ping(char *szDestIP, PingReply *pPingReply, DWORD dwTimeout)
{
	if (NULL != szDestIP)
	{
		return PingCore(inet_addr(szDestIP), pPingReply, dwTimeout);
	}
	return FALSE;
}

BOOL CPing::PingCore(DWORD dwDestIP, PingReply *pPingReply, DWORD dwTimeout)
{
	//判断初始化是否成功  
	if (!m_bIsInitSucc)
	{
		return FALSE;
	}

	//配置SOCKET  
	sockaddr_in sockaddrDest;
	sockaddrDest.sin_family = AF_INET;
	sockaddrDest.sin_addr.s_addr = dwDestIP;
	int nSockaddrDestSize = sizeof(sockaddrDest);

	//构建ICMP包  
	int nICMPDataSize = DEF_PACKET_SIZE + sizeof(ICMPHeader);
	ULONG ulSendTimestamp = GetTickCountCalibrate();
	USHORT usSeq = ++s_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 = usSeq;
	pICMPHeader->m_ulTimeStamp = ulSendTimestamp;
	pICMPHeader->m_usChecksum = CalCheckSum((USHORT*)m_szICMPData, nICMPDataSize);

	//发送ICMP报文  
	if (sendto(m_sockRaw, m_szICMPData, nICMPDataSize, 0, (struct sockaddr*)&sockaddrDest, nSockaddrDestSize) == SOCKET_ERROR)
	{
		return FALSE;
	}

	//判断是否需要接收相应报文  
	if (pPingReply == NULL)
	{
		return TRUE;
	}

	char recvbuf[256] = { "\0" };
	while (TRUE)
	{
		//接收响应报文  
		if (WSAWaitForMultipleEvents(1, &m_event, FALSE, 100, FALSE) != WSA_WAIT_TIMEOUT)
		{
			WSANETWORKEVENTS netEvent;
			WSAEnumNetworkEvents(m_sockRaw, m_event, &netEvent);

			if (netEvent.lNetworkEvents & FD_READ)
			{
				ULONG nRecvTimestamp = GetTickCountCalibrate();
				int nPacketSize = recvfrom(m_sockRaw, recvbuf, 256, 0, (struct sockaddr*)&sockaddrDest, &nSockaddrDestSize);
				if (nPacketSize != SOCKET_ERROR)
				{
					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 == usSeq //是本次请求报文的响应报文  
						)
					{
						pPingReply->m_usSeq = usSeq;
						pPingReply->m_dwRoundTripTime = nRecvTimestamp - pICMPHeader->m_ulTimeStamp;
						pPingReply->m_dwBytes = nPacketSize - usIPHeaderLen - sizeof(ICMPHeader);
						pPingReply->m_dwTTL = pIPHeader->m_byTTL;
						return TRUE;
					}
				}
			}
		}
		//超时  
		if (GetTickCountCalibrate() - ulSendTimestamp >= dwTimeout)
		{
			return FALSE;
		}
	}
}

USHORT CPing::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);
}

ULONG CPing::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);
}



其中A类使用:

加上头文件

CPing Ping;
int su = 0;
su = Ping.Ping("www.baidu.com",4,1000);//域名或者IP地址,ping的次数,超时事件

判断su的值,如果为-1即为异常,0为没有ping同,4为ping通


B类使用:

头文件

CPing objPing;
PingReply reply;
memset(&reply, 0, sizeof reply);

//DWORD dwAddress = ntohl(inet_addr("195.6.4.52"));CString转换为DWORD

while (TRUE)
{
objPing.Ping("195.6.4.52", &reply);
if (reply.m_dwBytes == 0)
{
m_ping = false;//失败
MessageBox("失败");
break;
}
else//ping通了  
{
m_ping = true;
MessageBox("成功");
}
}

这个类使用不是很方便,无法使用CString或者DWORD的IP地址来判断,只是使用简单的确定的ip地址来ping,


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值