头文件:Ping.h
#ifndef __checkmachine__
#define __checkmachine__
#include <winsock.h>
#include <windows.h>
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned char uchar;
typedef struct icmp_hdr
{
uchar type; //1
uchar code; //1
ushort checksum; //2
//other data
ushort id; //2
ushort sequence; //2
uint timestamp; //4
}ICMP; //12B
#define BUFLEN 0//32
#define IPHEADLEN 20
#define TIMEOUT 1
#define IPLEN 16
class kyPing
{
SOCKET mSocket;
SOCKADDR_IN mDest;
ushort mProcessId; //icmp's sequence
char mSendBuf[sizeof(ICMP) + BUFLEN]; //send icmp data
//char mRecvBuf[sizeof(ICMP) + BUFLEN]; //暂时做法
char mRecvBuf[1024];
uint mRecvLen;
HANDLE mLock;
public:
kyPing();
~kyPing();
//void run();
bool Init();
bool PingSend(char* ip, ushort seq = 0);
bool PingRecv();
private:
void PackSendBuf(uint seq);
bool UnPackRecvBuf();
ushort CheckICMPSum(ushort* buf, int size);
bool SetTimeout(int nTime, bool bRecv);
};
#endif
源文件:Ping.cpp
#include "Check.h"
#include <string.h>
#include <stdio.h>
kyPing::kyPing()
{
memset(&mDest, 0, sizeof(SOCKADDR_IN));
mDest.sin_family = AF_INET;
mRecvLen = 0;
// if(ip != NULL || (strlen(ip) + 1) < IPLEN) //不进行检查,要确保正确
// {
// mDest.sin_addr.S_un.S_addr = inet_addr(ip);
// }
}
kyPing::~kyPing()
{
closesocket(mSocket);
mSocket = 0;
WSACleanup();
}
bool kyPing::Init()
{
WSADATA wsaData;
if(::WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
return false;
}
//raw socket
mSocket = ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if(mSocket == INVALID_SOCKET)
{
return false;
}
SetTimeout(TIMEOUT * 1000, true);
mProcessId = (ushort)::GetCurrentProcessId();
//init buffer info
memset(mSendBuf, 0, sizeof(mSendBuf));
ICMP* icmp = (ICMP*)mSendBuf;
icmp->type = 8; //require icmp return show
icmp->id = mProcessId;
if(BUFLEN > 0)
memset(&mSendBuf[sizeof(ICMP)], 1, BUFLEN); //data
mLock = CreateMutex(NULL, false, NULL);
return true;
}
bool kyPing::PingSend(char* ip, ushort seq)
{
int len = sizeof(mSendBuf);
::WaitForSingleObject(mLock, INFINITE);
mDest.sin_addr.S_un.S_addr = inet_addr(ip); //没有进行ip检查,要确保正确
PackSendBuf(seq);
if(len != ::sendto(mSocket, mSendBuf, len, 0, (SOCKADDR*)&mDest, sizeof(SOCKADDR_IN)))
{
printf("sendtto error: %d!/n", WSAGetLastError());
ReleaseMutex(mLock);
return false;
}
ReleaseMutex(mLock);
return true;
}
bool kyPing::PingRecv()
{
SOCKADDR_IN from;
int len = sizeof(SOCKADDR_IN);
::WaitForSingleObject(mLock, INFINITE);
memset(mRecvBuf, 0, sizeof(mRecvBuf));
mRecvLen = ::recvfrom(mSocket, mRecvBuf, sizeof(mRecvBuf), 0, (sockaddr*)&from, &len);
if(SOCKET_ERROR != mRecvLen)
{
if(UnPackRecvBuf())
{
ReleaseMutex(mLock);
return true;
}
}
ReleaseMutex(mLock);
printf("recvfrom error: %d!/n", WSAGetLastError());
return false;
}
//contruct icmp_head data
void kyPing::PackSendBuf(uint seq)
{
ICMP* icmp = (ICMP*)mSendBuf;
icmp->checksum = 0;
icmp->sequence = seq; //***** can use to array[ip]'s no
icmp->timestamp = ::GetTickCount();
icmp->checksum = CheckICMPSum((ushort*)mSendBuf, sizeof(mSendBuf));
}
bool kyPing::UnPackRecvBuf()
{
if(mRecvLen < (sizeof(ICMP) + IPHEADLEN)) //len too smaller, drop
{
printf("error: recv data too lower!/n");
return false;
}
ICMP* icmp = (ICMP*)&mRecvBuf[IPHEADLEN];
if(icmp->id != mProcessId) //other packet
{
printf("error: other packet!/n");
return false;
}
if(icmp->type == 0)
{
//mStatus = 1;
//calculate spending time, test
printf("recv %dbyte, spend time: %dms/n", mRecvLen, ::GetTickCount() - icmp->timestamp);
}
return true;
}
ushort kyPing::CheckICMPSum(ushort* buf, int size)
{
uint cksum = 0;
while(size > 1)
{
cksum += *buf++;
size -= sizeof(USHORT);
}
if(size)
{
cksum += *(uchar*)buf;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
return (ushort)(~cksum);
}
bool kyPing::SetTimeout(int nTime, bool bRecv)
{
int ret = ::setsockopt(mSocket, SOL_SOCKET,
bRecv ? SO_RCVTIMEO : SO_SNDTIMEO, (char*)&nTime, sizeof(nTime));
return ret != SOCKET_ERROR;
}
测试文件:test.cpp
#include "Check.h"
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
DWORD __stdcall ProSend(void* param);
DWORD __stdcall ProRecv(void* param);
//char ip[3][2] = {1, 2, 3, 4, 5, 6}; //3line 2row
char* szIP = "220.181.6.18";
char ip[3][16] = {0};
void ImitateIP()
{
strcpy((char*)&ip[0], "220.181.6.18");
strcpy((char*)&ip[1], "61.135.253.12");
strcpy((char*)&ip[2], "127.0.0.1");
}
void main()
{
int i = 0;
ImitateIP();
printf("%s/n%s/n%s/n", ip[0], ip[1], ip[2]);
/*
uint ul = 1;
::ioctlsocket(sRaw, FIONBIO, (uint*)&ul);
*/
kyPing Ping;
if(!Ping.Init())
{
printf("ping init error()!/n");
return;
}
DWORD thrdID;
if(NULL == CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ProSend, &Ping, 0, &thrdID))
{
printf("create send thread failed!/n");
}
if(NULL == CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ProRecv, &Ping, 0, &thrdID))
{
printf("create recv thread failed!/n");
}
getchar();
}
DWORD __stdcall ProSend(void* param)
{
kyPing* Ping = (kyPing*)param;
int i = 0;
while(i < 3)
{
if(Ping->PingSend((char*)&ip[i], i))
{
printf("send success!/n");
}
i++;
/*
while(!Ping->PingRecv())
{
Sleep(1000);
}
*/
}
printf("thread ProSend exit!/n");
return 0;
}
DWORD __stdcall ProRecv(void* param)
{
printf("***thread ProRecv start!/n");;
kyPing* Ping = (kyPing*)param;
while(!Ping->PingRecv())
{
Sleep(1000);
}
while(!Ping->PingRecv())
{
Sleep(1000);
}
printf("***thread ProRecv exit!/n");
return 0;
}