用VC编写实现ping 功能的动态连接库

本文详细介绍了如何使用 C 语言实现 ICMP 协议的 Ping 功能。通过定义 IP 和 ICMP 数据包结构,实现了发送 Echo 请求及接收 Echo 回复的过程,并计算了往返时间。此外,还展示了如何创建 Raw 套接字并使用 WinSock 进行网络通信。

#include <afxsock.h>
#define ICMP_ECHOREPLY0
#define ICMP_ECHOREQ8
// IP Header -- RFC 791
typedef struct tagIPHDR
{
u_char VIHL;// Version and IHL
u_charTOS;// Type Of Service
shortTotLen;// Total Length
shortID;// Identification
shortFlagOff;// Flags and Fragment Offset
u_charTTL;// Time To Live
u_charProtocol;// Protocol
u_shortChecksum;// Checksum
structin_addr iaSrc;// Internet Address - Source
structin_addr iaDst;// Internet Address - Destination
}IPHDR, *PIPHDR;


// ICMP Header - RFC 792
typedef struct tagICMPHDR
{
u_charType;// Type
u_charCode;// Code
u_shortChecksum;// Checksum
u_shortID;// Identification
u_shortSeq;// Sequence
charData;// Data
}ICMPHDR, *PICMPHDR;


#define REQ_DATASIZE 32// Echo Request Data size

// ICMP Echo Request
typedef struct tagECHOREQUEST
{
ICMPHDR icmpHdr;
DWORDdwTime;
charcData[REQ_DATASIZE];
}ECHOREQUEST, *PECHOREQUEST;


// ICMP Echo Reply
typedef struct tagECHOREPLY
{
IPHDRipHdr;
ECHOREQUESTechoRequest;
char cFiller[256];
}ECHOREPLY, *PECHOREPLY;

u_short in_cksum(u_short *addr, int len)
{
int nleft = len;
u_short *w = addr;
u_short answer;
int sum = 0;
while( nleft > 1 ) {
sum += *w++;
nleft -= 2;
}

if( nleft == 1 ) {
u_shortu = 0;

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

sum = (sum >> 16) + (sum & 0xffff);/* add hi 16 to low 16 */
sum += (sum >> 16);/* add carry */
answer = ~sum;/* truncate to 16 bits */
return (answer);
}


int 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));
}


unsigned int 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

// Check return value

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

return(echoReply.echoRequest.dwTime);
}

extern "C" _declspec (dllexport)BOOL Ping(CString pstrHost, UINT nNumIp)
{
ECHOREQUEST echoReq;
int nId = 1;
int nSeq = 1;
SOCKET rawSocket;
LPHOSTENT lpHost;
UINT nLoop;
int nRet;
struct sockaddr_in saDest;
struct sockaddr_in saSrc;
DWORD dwTimeSent;
DWORD dwElapsed;
u_char cTTL;
char *destIP = NULL;
WSADATA wsaData;
//创建一个Raw套节字
if(WSAStartup(MAKEWORD(2,1), &wsaData))
{
return false;
}
rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (rawSocket == SOCKET_ERROR)
{
nRet = closesocket(rawSocket);
::WSACleanup();
return FALSE;
}
//获得主机信息
lpHost = gethostbyname(pstrHost);
if (lpHost == NULL)
{
nRet = closesocket(rawSocket);
::WSACleanup();
return FALSE;
}
//构造目标套节字地址信息
memset(&saDest, 0, sizeof(sockaddr_in));
saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr));
saDest.sin_family = AF_INET;
saDest.sin_port = 0;
//发送ICMP回应请求

//SendEchoRequest(rawSocket,&saDest);


int rnRet;

echoReq.icmpHdr.Type= ICMP_ECHOREQ;
echoReq.icmpHdr.Code= 0;
echoReq.icmpHdr.Checksum= 0;
echoReq.icmpHdr.ID= nId++;
echoReq.icmpHdr.Seq= nSeq++;

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

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

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

// Send the echo request
rnRet = sendto(rawSocket,/* socket */
(LPSTR)&echoReq,/* buffer */
sizeof(ECHOREQUEST),
0,/* flags */
(LPSOCKADDR)&saDest, /* destination */
sizeof(SOCKADDR_IN)); /* address length */
if (rnRet == SOCKET_ERROR)
{
rnRet = closesocket(rawSocket);
::WSACleanup();
return FALSE;
}

nRet = WaitForEchoReply(rawSocket);
if (nRet == SOCKET_ERROR){
nRet = closesocket(rawSocket);
::WSACleanup();
return FALSE;
}
if(!nRet){
nRet = closesocket(rawSocket);
::WSACleanup();
return FALSE;
}
else{
//获得回应
dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL);
//计算时间
dwElapsed = GetTickCount() - dwTimeSent;
::Sleep(1000);
destIP = inet_ntoa(saSrc.sin_addr);//获得客户IP地址
if(pstrHost == destIP){
nRet = closesocket(rawSocket);
nRet = ::WSACleanup();
return TRUE;
}
else
{
for(nLoop = 0; nLoop < nNumIp; nLoop++)
{
dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL);
destIP = inet_ntoa(saSrc.sin_addr);
if(pstrHost == destIP)
{
nRet = closesocket(rawSocket);
nRet = ::WSACleanup();
return TRUE;
}
}
nRet = closesocket(rawSocket);
nRet = ::WSACleanup();
return FALSE;
}
}
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值