代码如下:
1.main函数
#include<WinSock2.h>
#include<stdio.h>
#include"ping.h"
int main(void)
{
CPing objPing;
char DestIP[] = "172.22.56.231";
PingReply reply;
printf("Pinging %s with %d bytes of data:\n", DestIP, DEF_PACKET_SIZE);
while (TRUE)
{
objPing.Ping(DestIP, &reply);
printf("Reply from %s: bytes=%d time=%ldms TTL=%ld\n", DestIP,reply.re_Bytes , reply.re_RoundTripTime, reply.re_TTL);
Sleep(500);
}
return 0;
}
2.ping.h头文件
#pragma once
#include<WinSock2.h>
#pragma comment(lib,"WS2_32")
#define DEF_PACKET_SIZE 32
#define ECHO_REQUEST 8
#define ECHO_REPLY 0
struct IPHeader
{
BYTE ip_VerAndLen; //版本长度和首部长度
BYTE ip_ServiceType; //服务类型
USHORT ip_TotalLen; //总长度
USHORT ip_ID;//标识
USHORT ip_MarkAndSliceOffset;//标志和片偏移
BYTE ip_TTL; //生存时间
BYTE ip_Protocol;//协议
USHORT ip_HeaderCheckSum;//首部检验和
ULONG ip_SrcIP; //源IP
LONG ip_DestIP; //目的IP
};
struct ICMPHeader
{
BYTE icmp_Type; //类型(取0或者8)
BYTE icmp_Code; //代码
USHORT icmp_CheckSum;//校验和
USHORT icmp_ID; //标识符
USHORT icmp_Seq; //序号
ULONG icmp_TimeStamp; //时间戳
};
//回应结构体
struct PingReply
{
USHORT re_Seq;
DWORD re_RoundTripTime;
DWORD re_Bytes;
DWORD re_TTL;
};
class CPing
{
public :
CPing();
~CPing();
BOOL Ping(DWORD DestIP, PingReply* pPingReply = NULL, DWORD timeOut = 2000);
BOOL Ping(char* DestIP, PingReply* pPingReply = NULL, DWORD timeOut = 2000);
private :
BOOL PingCore(DWORD DestIP, PingReply* pPingReply, DWORD timeOut);
USHORT CalCheckSum(USHORT* pBuffer, int nSize);
ULONG GetTickCountCalibrate();
private :
SOCKET my_socketRaw;
WSAEVENT my_event;
USHORT my_CurrentProcID;
char* my_ICMPData;
BOOL my_InitSucc;
private :
static USHORT my_PacketSeq;
};
3.ping.cpp文件
#pragma warning (disable:4996)
#include"ping.h"
#include<iostream>
USHORT CPing::my_PacketSeq = 0;
CPing::CPing() :my_ICMPData(NULL), my_InitSucc(FALSE)
{
WSADATA WSAData;
if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
{
//初始化不成功就会报错
printf("WSAStartup() failed: %d\n", GetLastError());
return;
}
my_event = WSACreateEvent();
my_CurrentProcID = (USHORT)GetCurrentProcessId();
my_socketRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, 0);
if (my_socketRaw == INVALID_SOCKET)
{
std::cerr << " WSASOcket() failed " << WSAGetLastError() << std::endl;
}
else
{
WSAEventSelect(my_socketRaw, my_event, FD_READ);
my_InitSucc = TRUE;
my_ICMPData = (char*)malloc(DEF_PACKET_SIZE + sizeof(ICMPHeader));
if (my_ICMPData == NULL)
{
my_InitSucc = FALSE;
}
}
}
CPing::~CPing()
{
WSACleanup();
if (NULL != my_ICMPData)
{
free(my_ICMPData);
my_ICMPData = NULL;
}
}
BOOL CPing::Ping(DWORD DestIP, PingReply* pPingReply, DWORD timeOut)
{
return PingCore(DestIP, pPingReply, timeOut);
}
BOOL CPing::Ping(char* DestIP, PingReply* pPingReply, DWORD timeOut)
{
if (NULL != DestIP)
{
return PingCore(inet_addr(DestIP), pPingReply, timeOut);
}
return FALSE;
}
BOOL CPing::PingCore(DWORD DestIP, PingReply* pPingReply, DWORD timeOut)
{
if (!my_InitSucc)
{
return FALSE;
}
//配置SOCKET
sockaddr_in sockaddrDest;
sockaddrDest.sin_family = AF_INET;
sockaddrDest.sin_addr.s_addr = DestIP;
int nSockaddrDestSize = sizeof(sockaddrDest);
//构建ICMP包
int nICMPDataSize = DEF_PACKET_SIZE + sizeof(ICMPHeader);
ULONG usSendTimestamp = GetTickCountCalibrate();
USHORT usSeq = ++my_PacketSeq;
memset(my_ICMPData, 0, nICMPDataSize);
ICMPHeader* pICMPHeader = (ICMPHeader*)my_ICMPData;
pICMPHeader->icmp_Type = ECHO_REQUEST;
pICMPHeader->icmp_Code = 0;
pICMPHeader->icmp_ID = my_CurrentProcID;
pICMPHeader->icmp_Seq = usSeq;
pICMPHeader->icmp_TimeStamp = usSendTimestamp;
pICMPHeader->icmp_CheckSum = CalCheckSum((USHORT*)my_ICMPData, nICMPDataSize);
//发送ICMP报文
if (sendto(my_socketRaw, my_ICMPData, nICMPDataSize, 0, (struct sockaddr*)&sockaddrDest, nSockaddrDestSize) == SOCKET_ERROR)
{
return FALSE;
}
//判断是否需要接收相应报文
if (pPingReply == NULL)
{
return TRUE;
}
char recvbuf[256] = { "\0" };
while (TRUE)
{
//接收响应报文
if (WSAWaitForMultipleEvents(1, &my_event, FALSE, 100, FALSE) != WSA_WAIT_TIMEOUT)
{
WSANETWORKEVENTS netEvent;
WSAEnumNetworkEvents(my_socketRaw, my_event, &netEvent);
if (netEvent.lNetworkEvents & FD_READ)
{
ULONG nRecvTimestamp = GetTickCountCalibrate();
int nPacketSize = recvfrom(my_socketRaw, recvbuf, 256, 0, (struct sockaddr*)&sockaddrDest, &nSockaddrDestSize);
if (nPacketSize != SOCKET_ERROR)
{
IPHeader* pIPHeader = (IPHeader*)recvbuf;
USHORT usIPHeaderLen = (USHORT)((pIPHeader->ip_VerAndLen & 0x0f) * 4);
ICMPHeader* pICMPHeader = (ICMPHeader*)(recvbuf + usIPHeaderLen);
if (pICMPHeader->icmp_ID == my_CurrentProcID
&& pICMPHeader->icmp_Type == ECHO_REPLY
&& pICMPHeader->icmp_Seq == usSeq
)
{
pPingReply->re_Seq = usSeq;
pPingReply->re_RoundTripTime = nRecvTimestamp - pICMPHeader->icmp_TimeStamp;
pPingReply->re_Bytes = nPacketSize - usIPHeaderLen - sizeof(ICMPHeader);
pPingReply->re_TTL = pIPHeader->ip_TTL;
return TRUE;
}
}
}
}
if (GetTickCountCalibrate() - usSendTimestamp >= timeOut)
{
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 ULONG 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);
}
参考博客:https://www.cnblogs.com/ranjiewen/p/5704627.html