您的位置:首页 > 其它

一种比较简单的实现ping的方式

2015-05-04 16:17 417 查看
<span style="font-family: Arial, Helvetica, sans-serif;">头文件</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">#ifndef __PING_H__</span>
#define __PING_H__
//
// Ping.h
//
#pragma once
#pragma pack(1)

#include <winsock2.h>

#define ICMP_ECHOREPLY	0
#define ICMP_ECHOREQ	8

#define PINGERR_SOCKET_ERROR -1
#define PINGERR_TIMEOUT      -2
#define PINGERR_NOHOST       -3
class CPing
{
public:
int Ping(int ip);

protected:
int  WaitForEchoReply(SOCKET s);
// ICMP Echo Request/Reply functions
int		SendEchoRequest(SOCKET, LPSOCKADDR_IN);
DWORD	RecvEchoReply(SOCKET, LPSOCKADDR_IN, u_char *);
u_short in_cksum(u_short *addr, int len);
};

// IP Header -- RFC 791
typedef struct tagIPHDR
{
u_char  VIHL;			// Version and IHL
u_char	TOS;			// Type Of Service
short	TotLen;			// Total Length
short	ID;				// Identification
short	FlagOff;		// Flags and Fragment Offset
u_char	TTL;			// Time To Live
u_char	Protocol;		// Protocol
u_short	Checksum;		// Checksum
struct	in_addr iaSrc;	// Internet Address - Source
struct	in_addr iaDst;	// Internet Address - Destination
}IPHDR, *PIPHDR;

// ICMP Header - RFC 792
typedef struct tagICMPHDR
{
u_char	Type;			// Type
u_char	Code;			// Code
u_short	Checksum;		// Checksum
u_short	ID;				// Identification
u_short	Seq;			// Sequence
char	Data;			// Data
}ICMPHDR, *PICMPHDR;

#define REQ_DATASIZE 32		// Echo Request Data size

// ICMP Echo Request
typedef struct tagECHOREQUEST
{
ICMPHDR icmpHdr;
DWORD	dwTime;
char	cData[REQ_DATASIZE];
}ECHOREQUEST, *PECHOREQUEST;

// ICMP Echo Reply
typedef struct tagECHOREPLY
{
IPHDR	ipHdr;
ECHOREQUEST	echoRequest;
char    cFiller[256];
}ECHOREPLY, *PECHOREPLY;

#pragma pack()

#endif


实现

//
// THIS CODE IS BASED ON THE CODE FROM
// THE BOOK WINSOCK 2.0 BY LEWIS NAPPER...
//
//

#include "ping.h"
#include <Mmsystem.h>
#pragma comment( lib,"winmm.lib" )
#pragma comment(lib,"ws2_32.lib")

int CPing::Ping(int ip)
{
SOCKET	  rawSocket;
int       nRet;
struct    sockaddr_in saDest;
struct    sockaddr_in saSrc;
DWORD	  dwTimeSent;
DWORD	  dwElapsed;
u_char    cTTL;

// Create a Raw socket
rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (rawSocket == SOCKET_ERROR)
{
return PINGERR_SOCKET_ERROR;
}

// Setup destination socket address
saDest.sin_addr.s_addr = ip;
saDest.sin_family = AF_INET;
saDest.sin_port   = 0;

// Send ICMP echo request
SendEchoRequest(rawSocket, &saDest);

nRet = WaitForEchoReply(rawSocket);
if (nRet == SOCKET_ERROR)
{
return PINGERR_SOCKET_ERROR;
}

if (!nRet)
{
return PINGERR_TIMEOUT;
}
else
{
// Receive reply
dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL);
// Calculate elapsed time
dwElapsed = timeGetTime() - dwTimeSent;

}
nRet = closesocket(rawSocket);

return (int)dwElapsed;
}

int CPing::SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr)
{
static ECHOREQUEST echoReq;
static int nId = 1;
static int nSeq = 1;
int nRet;

// Fill in echo request
echoReq.icmpHdr.Type		= ICMP_ECHOREQ;
echoReq.icmpHdr.Code		= 0;
echoReq.icmpHdr.Checksum	= 0;
echoReq.icmpHdr.ID			= u_short(nId++);
echoReq.icmpHdr.Seq			= u_short(nSeq++);

// Fill in some data to send
for (nRet = 0; nRet < REQ_DATASIZE; nRet++)
echoReq.cData[nRet] = char(' '+nRet);

// Save tick count when sent
echoReq.dwTime				= timeGetTime();

// Put data in packet and compute checksum
echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST));

// Send the echo request
nRet = sendto(s,						/* socket */
(LPSTR)&echoReq,			/* buffer */
sizeof(ECHOREQUEST),
0,							/* flags */
(LPSOCKADDR)lpstToAddr, /* destination */
sizeof(SOCKADDR_IN));   /* address length */

return (nRet);
}

DWORD CPing::RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL)
{
ECHOREPLY echoReply;
int nRet;
int nAddrLen = sizeof(struct sockaddr_in);

// Receive the echo reply
nRet = recvfrom(s,					// socket
(LPSTR)&echoReply,	// buffer
sizeof(ECHOREPLY),	// size of buffer
0,					// flags
(LPSOCKADDR)lpsaFrom,	// From address
&nAddrLen);			// pointer to address len

// return time sent and IP TTL
*pTTL = echoReply.ipHdr.TTL;

return(echoReply.echoRequest.dwTime);
}

int CPing::WaitForEchoReply(SOCKET s)
{
struct timeval Timeout;
fd_set readfds;

readfds.fd_count = 1;
readfds.fd_array[0] = s;
Timeout.tv_sec = 1;
Timeout.tv_usec = 0;

return(select(1, &readfds, NULL, NULL, &Timeout));
}

//
// Mike Muuss' in_cksum() function
// and his comments from the original
// ping program
//
// * Author -
// *	Mike Muuss
// *	U. S. Army Ballistic Research Laboratory
// *	December, 1983

/*
*			I N _ C K S U M
*
* Checksum routine for Internet Protocol family headers (C Version)
*
*/
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;

/*
*  Our algorithm is simple, using a 32 bit accumulator (sum),
*  we add sequential 16 bit words to it, and at the end, fold
*  back all the carry bits from the top 16 bits into the lower
*  16 bits.
*/
while( nleft > 1 )  {
sum += *w++;
nleft -= 2;
}

/* mop up an odd byte, if necessary */
if( nleft == 1 ) {
u_short	u = 0;

*(u_char *)(&u) = *(u_char *)w ;
sum += u;
}

/*
* add back carry outs from top 16 bits to low 16 bits
*/
sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
sum += (sum >> 16);			/* add carry */
answer = u_short(~sum);				/* truncate to 16 bits */
return (answer);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: