一种比较简单的实现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); }
相关文章推荐
- Android无网络状态下使用GPS定位到省市县的一种简单实现方式
- Android弹出式菜单-一种简单的实现方式
- C#使用命令行方式实现Ping简单功能 http://www.cnblogs.com/kevinton/archive/2007/06/28/798581.html
- java实现多线程的一种简单方式
- 一种简单的方式实现Cocos2d-x 2.x版本按层级关系派发Touch事件
- minigui界面生成工具的一种简单实现方式,轻松实现Windows/linux minigui 跨平台界面编程
- 快排的一种相当简单但不算最快的实现方式
- HorizontalListView 中 setSelection() 一种简单实现方式
- APP中一种在Java层实现的简单守护进程方式
- Preferences(首选项)(恢复默认功能)的一种简单的实现方式
- 多线程中的全局信息统计的一种简单实现方式(java实现)
- 利用hadoop命令rcc生成Record 一种简单的方式实现自定义的writable对象
- 19. Unity NGUI-屏幕自适应,最简单的一种实现方式
- APP中一种在Java层实现的简单守护进程方式
- APP中一种在Java层实现的简单守护进程方式
- Android动态图片选择的一种简单实现方式
- 【图说】介绍一种简单方式,实现缺陷与SVN的代码相关联,并能自动展现Code修改前后对比
- 一种偷懒方式实现心电图(Xfermode简单应用)
- 一种简单的小型企业报表实现方式
- C#使用命令行方式实现Ping简单功能