CPing.h
// Ping.h: interface for the CPing class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_PING_H__2EBF2C11_A0A3_403B_9EB2_1905CFF8EE58__INCLUDED_)
#define AFX_PING_H__2EBF2C11_A0A3_403B_9EB2_1905CFF8EE58__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include<Winsock.h>
#include<stdlib.h>
#include<stdio.h>
#pragma comment(lib,"ws2_32.lib")
#define ICMP_ECHOREPLY 0
#define ICMP_ECHOREQ 8
//////////////////////////////////
typedef struct tagIPDR
{
u_char VIHL;//版本和類型
u_char TOS;//服務質量
u_char shortTotLen;//長度
u_char shortID;//編號
u_char shortFlagOff;//分片,Fragment
u_char TTL;//生存時間
u_char Protocol;//協議類型
u_short Checksum;//校驗和
struct in_addr iaSrc;//源地址
struct in_addr isDet;//目的地址
}IPHDR,*PIPHDR;//RFC791 的IP協議頭類型
////////////////////////////////////////
typedef struct tagICMP
{
u_char Type;//類型
u_char Code;//代號
u_short Checksum;//校驗號
u_short ID;//標識號
u_short Seq;//列號
char Data;//數據信息
}ICMPHDR,*PICMPHDR;//RFC 792 ICMP協議頭
/////////////////////////////////////////
#define REQ_DATASIZE 32
typedef struct tagECHOREQUEST
{
ICMPHDR icmpHdr;//ICMP協議頭
DWORD dwTime;//數據傳輸時間
char cData[REQ_DATASIZE];//傳輸數據
}ECHOREQUEST,*PECHOREQUEST;//請求回傳的數據長度
///////////////////////////////////////////////////
typedef struct tagECHOREPLY
{
IPHDR ipHdr;
ECHOREQUEST echoRequest;
char cFiler[256];
}ECHOREPLY,*PECHOREPLY;//回送請求報文
// 用於Ping的探測技術
class CPing
{
public:
CPing();
virtual ~CPing();
private:
void InitPing();
void CleanUP();
void ReportError(LPCSTR psrtFrom);
int WaitForEchoReply(SOCKET s);
int SendEchoRequest(SOCKET,LPSOCKADDR_IN);
DWORD RecvEchoReply(SOCKET,LPSOCKADDR_IN,char*);
u_short in_cksum(u_short *addr,int len);
public:
bool Ping(CString strIP);
CString LongIPToStr(long nIP);
long StrIPToLong(CString strIP);
private:
DWORD time;
};
#endif // !defined(AFX_PING_H__2EBF2C11_A0A3_403B_9EB2_1905CFF8EE58__INCLUDED_)
CPing.cpp
// Ping.cpp: implementation of the CPing class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Ping.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CPing::CPing()
{
InitPing();
}
CPing::~CPing()
{
CleanUP();
}
void CPing::InitPing()
{
WSADATA wsaData;
WORD version=MAKEWORD(1,1);
if(WSAStartup(version,&wsaData))
{
printf("初始化協議棧錯誤\n");
return ;
}
if(wsaData.wVersion!=version)
{
printf("不支持WIDOWS的套接字\n");
return ;
}
}
void CPing::CleanUP()
{
WSACleanup();
}
// 打印錯誤的代碼
void CPing::ReportError(LPCSTR psrtFrom)
{
printf("%s發生錯誤,錯誤號:%d\n",psrtFrom,WSAGetLastError());
}
// 等待迴應信息
int CPing::WaitForEchoReply(SOCKET s)
{
struct timeval Timeout;
fd_set readfds;
readfds.fd_count=1;
readfds.fd_array[0]=s;
Timeout.tv_sec=5;
Timeout.tv_usec=0;
return select(1,&readfds,NULL,NULL,&Timeout);
}
//發送請求信息
int CPing::SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr)
{
static ECHOREQUEST echoReq;
static nId=1;
static nSeq=1;
static nRet;
echoReq.icmpHdr.Type=ICMP_ECHOREQ;
echoReq.icmpHdr.Code=0;
echoReq.icmpHdr.Checksum=0;
echoReq.icmpHdr.ID=nId++;
echoReq.icmpHdr.Seq=nSeq++;
for(nRet=0;nRet<REQ_DATASIZE;nRet++)
echoReq.cData[nRet]=nRet;
echoReq.dwTime=GetTickCount();
time=echoReq.dwTime;//記錄發送時間
echoReq.icmpHdr.Checksum=in_cksum((u_short *)&echoReq,sizeof(ECHOREQUEST));
nRet=sendto(s,(LPCSTR)&echoReq,sizeof(ECHOREQUEST),0,(LPSOCKADDR)lpstToAddr,sizeof(SOCKADDR_IN));
if(nRet==SOCKET_ERROR)
ReportError("發送出錯");
return nRet;
}
// 接收回應的信息
DWORD CPing::RecvEchoReply(SOCKET s,LPSOCKADDR_IN lpsaFrom,char *pTTL)
{
ECHOREPLY echoReply;
int nRet;
int nAddrLen=sizeof(struct sockaddr_in);
nRet=recvfrom(s,(LPSTR)&echoReply,sizeof(ECHOREPLY),0,(LPSOCKADDR)lpsaFrom,&nAddrLen);
if(nRet==SOCKET_ERROR)
ReportError("接收");
*pTTL=echoReply.ipHdr.TTL;
return echoReply.echoRequest.dwTime;
}
// 檢驗和
u_short CPing::in_cksum(u_short *addr,int len)
{
register int nleft=len;
register u_short *w=addr;
register u_short answer;
register int sum=0;
while(nleft>1)
{
sum+=*w++;
nleft-=2;
}
if(nleft==1)
{
u_short u=0;
*(u_char *)(&u)=*(u_char *)w;
sum+=u;
}
sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
answer=~sum;
return answer;
}
// 探測某IP地址
bool CPing::Ping(CString strIP)
{
SOCKET rawSocket;
LPHOSTENT lpHost;
struct sockaddr_in saDest;
struct sockaddr_in saSrc;
DWORD dwTimeSent;
DWORD dwElapsed;
u_char cTTL;
int nLoop;
int nRet;
rawSocket=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
if(rawSocket==SOCKET_ERROR)
{
//ReportError("套接字");
return false;
}
lpHost=gethostbyname(strIP);
if(lpHost==NULL)
{
// printf("無法找到這主機[%s]\n",strIP);
return false;
}
saDest.sin_addr.s_addr=*((u_long FAR*)(lpHost->h_addr));
saDest.sin_family=AF_INET;
saDest.sin_port=0;
//printf("\n探測主機%s[%s]:%d字節\n",strIP,inet_ntoa(saDest.sin_addr),REQ_DATASIZE);
int nCount = 0;
for(nLoop=0;nLoop<4;nLoop++)
{
SendEchoRequest(rawSocket,&saDest);
nRet=WaitForEchoReply(rawSocket);
if(nRet==SOCKET_ERROR)
{
// ReportError("選擇");
break;
}
if(!nRet)
{
//printf("發送超時\n");
break;
}
dwTimeSent=RecvEchoReply(rawSocket,&saSrc,(char*)&cTTL);
dwElapsed=time-dwTimeSent;
nCount ++;
//printf("來自主機[%s]響應,字節:%d 時間:%ld毫秒 最大生存期:%d\n",inet_ntoa(saSrc.sin_addr),REQ_DATASIZE,dwElapsed,cTTL);
}
closesocket(rawSocket);
if(nCount > 2)
return true;
return false;
}
// 將長整性的IP地址,轉換成字符串型
CString CPing::LongIPToStr(long nIP)
{
struct in_addr addr;
addr.s_addr = htonl(nIP);
CString strIP;
strIP.Format("%s",inet_ntoa(addr));
return strIP;
}
// 將字符串型的IP地址,轉換成長整性
long CPing::StrIPToLong(CString strIP)
{
return ntohl(inet_addr(strIP));
}
調用代碼:
CPing ping;
bool flag = false;
flag = ping.Ping("172.0.0.1");