c++ ping 功能实现
2018-02-11 11:19
441 查看
#if !defined(COMMON_FDSET_H) #define COMMON_FDSET_H #include <cassert> #include <errno.h> #include <algorithm> #ifdef WIN32 //#include <winsock2.h> #include <WS2TCPIP.H> #include <stdlib.h> #include <io.h> #endif #ifndef WIN32 typedef int SOCKET; #define INVALID_SOCKET (-1) #define SOCKET_ERROR (-1) #else //typedef SOCKET SOCKET; #endif int closeSocket( SOCKET fd ); class FdSet { public: FdSet() : size(0), numReady(0) { FD_ZERO(&read); FD_ZERO(&write); FD_ZERO(&except); } int select(struct timeval& tv) { return numReady = ::select(size, &read, &write, &except, &tv); } int selectMilliSeconds(unsigned long ms) { struct timeval tv; tv.tv_sec = (ms/1000); tv.tv_usec = (ms%1000)*1000; return select(tv); } bool readyToRead(SOCKET fd) { return (FD_ISSET(fd, &read) != 0); } bool readyToWrite(SOCKET fd) { return (FD_ISSET(fd, &write) != 0); } bool hasException(SOCKET fd) { return (FD_ISSET(fd,&except) != 0); } void setRead(SOCKET fd) { assert( FD_SETSIZE >= 8 ); FD_SET(fd, &read); size = ( int(fd+1) > size) ? int(fd+1) : size; } void setWrite(SOCKET fd) { FD_SET(fd, &write); size = ( int(fd+1) > size) ? int(fd+1) : size; } void setExcept(SOCKET fd) { FD_SET(fd,&except); size = ( int(fd+1) > size) ? int(fd+1) : size; } void clear(SOCKET fd) { FD_CLR(fd, &read); FD_CLR(fd, &write); FD_CLR(fd, &except); } void reset() { size = 0; numReady = 0; FD_ZERO(&read); FD_ZERO(&write); FD_ZERO(&except); } // Make this stuff public for async dns/ares to use fd_set read; fd_set write; fd_set except; int size; int numReady; // set after each select call }; #endif
#include <assert.h> #include <fcntl.h> #ifndef WIN32 #include <errno.h> #include <unistd.h> #endif #include "FdSet.h" using namespace std; #ifdef WIN32 typedef int socklen_t; #define EWOULDBLOCK WSAEWOULDBLOCK #define EINPROGRESS WSAEINPROGRESS #define EALREADY WSAEALREADY #define ENOTSOCK WSAENOTSOCK #define EDESTADDRREQ WSAEDESTADDRREQ #define EMSGSIZE WSAEMSGSIZE #define EPROTOTYPE WSAEPROTOTYPE #define ENOPROTOOPT WSAENOPROTOOPT #define EPROTONOSUPPORT WSAEPROTONOSUPPORT #define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT #define EOPNOTSUPP WSAEOPNOTSUPP #define EPFNOSUPPORT WSAEPFNOSUPPORT #define EAFNOSUPPORT WSAEAFNOSUPPORT #define EADDRINUSE WSAEADDRINUSE #define EADDRNOTAVAIL WSAEADDRNOTAVAIL #define ENETDOWN WSAENETDOWN #define ENETUNREACH WSAENETUNREACH #define ENETRESET WSAENETRESET #define ECONNABORTED WSAECONNABORTED #define ECONNRESET WSAECONNRESET #define ENOBUFS WSAENOBUFS #define EISCONN WSAEISCONN #define ENOTCONN WSAENOTCONN #define ESHUTDOWN WSAESHUTDOWN #define ETOOMANYREFS WSAETOOMANYREFS #define ETIMEDOUT WSAETIMEDOUT #define ECONNREFUSED WSAECONNREFUSED #define ELOOP WSAELOOP #define EHOSTDOWN WSAEHOSTDOWN #define EHOSTUNREACH WSAEHOSTUNREACH #define EPROCLIM WSAEPROCLIM #define EUSERS WSAEUSERS #define EDQUOT WSAEDQUOT #define ESTALE WSAESTALE #define EREMOTE WSAEREMOTE #else #define WSANOTINITIALISED EPROTONOSUPPORT #endif int closeSocket( SOCKET fd ) { #if defined(WIN32) return closesocket(fd); #else int ret = ::close(fd); return ret; #endif }
#ifndef __SocketPing_H__ #define __SocketPing_H__ #include "FdSet.h" #define ICMP_ECHO 8 #define ICMP_ECHOREPLY 0 #define ICMP_MIN 8 // minimum 8 byte icmp packet (just header) #define ICMP_MAGIC 2010 #define STATUS_FAILED 0xFFFF #define DEF_PACKET_SIZE 32 #define MAX_PACKET 1024 /* The IP header */ typedef struct ip_hdr { unsigned int h_len:4; // length of the header unsigned int version:4; // Version of IP unsigned char tos; // Type of service unsigned short total_len; // total length of the packet unsigned short ident; // unique identifier unsigned short frag_and_flags; // flags unsigned char ttl; unsigned char proto; // protocol (TCP, UDP etc) unsigned short checksum; // IP checksum unsigned int sourceIP; unsigned int destIP; }IpHeader; // // ICMP header // typedef struct _ihdr { BYTE i_type; BYTE i_code; /* type sub code */ USHORT i_cksum; USHORT i_id; USHORT i_seq; /* This is not the std header, but we reserve space for time */ ULONG timestamp; }IcmpHeader; //IP option header--use with socket option IP_OPTIONS typedef struct _ipoptionhdr { unsigned char code; // Option type unsigned char len; // Length of option hdr unsigned char ptr; // Offset into optons unsigned long addr[9]; // List of IP addrs } IpOptionHeader; // ping bool Ping(const char * ip, int try_count = 4, int timeout = 3000); #endif /*__SocketPing_H__*/
#include "SocketPing.h" /*lint -e830*/ static USHORT MakeIcmpID() { static CMutex g_mutex; CGuard guard(&g_mutex); static USHORT iIcmpID = 1; return iIcmpID++; } static USHORT checksum(USHORT *buffer, int size) { unsigned long cksum=0; while(size >1) { cksum += *buffer++; size -= sizeof(USHORT); } if(size ) { cksum += *(UCHAR*)buffer; } cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >>16); return (USHORT)(~cksum); } /* Helper function to fill in various stuff in our ICMP request. */ static void fill_icmp_data(char * icmp_data, int datasize, USHORT icmp_id) { IcmpHeader *icmp_hdr; char *datapart; icmp_hdr = (IcmpHeader*)icmp_data; icmp_hdr->i_type = ICMP_ECHO; icmp_hdr->i_code = 0; icmp_hdr->i_id = icmp_id;//ICMP_MAGIC; icmp_hdr->i_cksum = 0; icmp_hdr->i_seq = 0; datapart = icmp_data + sizeof(IcmpHeader); // // Place some junk in the buffer. // memset(datapart,'E', datasize - sizeof(IcmpHeader)); } /* The response is an IP packet. We must decode the IP header to locate the ICMP data //成功返回0;失败返回-1;如果收到别人回复返回1 */ static int decode_resp(char *buf, int bytes,struct sockaddr_in *from, const char * ip, USHORT icmp_id) { IpHeader * iphdr = (IpHeader *)buf; unsigned short iphdrlen = (unsigned short)iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes if (bytes < iphdrlen + ICMP_MIN) { SOCKETDEV_ERROR("Ping [%s] too few bytes", ip); return -1; } IcmpHeader *icmphdr = (IcmpHeader*)(buf + iphdrlen); if (icmphdr->i_type != ICMP_ECHOREPLY) { SOCKETDEV_ERROR("Ping [%s], no echo reply", ip, icmphdr->i_type); return -1; } if (icmphdr->i_id != icmp_id) { //SOCKET_LOG_ERROR("Ping [%s] error magic packet", ip); return 1; } return 0; } static bool send_icmp_data(SOCKET sock_raw, const char * ip, USHORT icmp_id, int try_count, int timeout) { int seq_no = 0; char icmp_data[MAX_PACKET] = {0}; sockaddr_in dest = {0}; dest.sin_family = AF_INET; dest.sin_addr.s_addr = inet_addr( ip ); bool success = false; bool needToSendPingReq = true; while(try_count-- > 0) { bool isToSendPingReq = needToSendPingReq; needToSendPingReq = true; if(isToSendPingReq) { memset(icmp_data,0,MAX_PACKET); fill_icmp_data(icmp_data, DEF_PACKET_SIZE, icmp_id); ((IcmpHeader*)icmp_data)->i_cksum = 0; ((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); ((IcmpHeader*)icmp_data)->i_seq = (unsigned short)seq_no++; ((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, DEF_PACKET_SIZE); int bwrote = sendto(sock_raw, icmp_data, DEF_PACKET_SIZE, 0, (struct sockaddr*)&dest, sizeof(dest)); if (bwrote == SOCKET_ERROR) { if (WSAGetLastError() == WSAETIMEDOUT) { SOCKETDEV_ERROR("Ping [%s] timed out", ip); continue; } SOCKETDEV_ERROR("Ping [%s] packet send failed: %d", ip, WSAGetLastError()); continue; } if (bwrote < DEF_PACKET_SIZE ) { continue; } } char recvbuf[MAX_PACKET] = {0}; struct sockaddr_in from; int fromlen = sizeof(from); FdSet fdset; fdset.setRead(sock_raw); timeval val; val.tv_sec = timeout / 1000; val.tv_usec = (timeout%1000)*1000; int bread = SOCKET_ERROR; bool bTimeout =false; do { int selectRet = fdset.select(val); if(selectRet == 0) {//超时 bTimeout = true; break; } else if(selectRet < 0) {//发生错误 break; } if(fdset.readyToRead(sock_raw)) { bread = recvfrom(sock_raw, recvbuf, MAX_PACKET, 0, (struct sockaddr*)&from, &fromlen); } } while (0); if(bTimeout || (bread <= 0 && WSAGetLastError() == WSAETIMEDOUT)) { SOCKETDEV_ERROR("Ping [%s] timed out", ip); continue; } if (bread <= 0) { SOCKETDEV_ERROR("Ping [%s] recv failed: %d", ip, WSAGetLastError()); continue; } int ret = decode_resp(recvbuf, bread, &from, ip, icmp_id); if(ret == 0) { success = true; break; } else if(ret == 1) { //接收了别的ping回复,需要重新接收 needToSendPingReq = false; ++ try_count; continue; } //失败 continue; } return success; } //ping bool Ping(const char * ip, int try_count, int timeout) { SOCKET sock_raw; bool success = false; USHORT icmp_id = MakeIcmpID(); do { sock_raw = WSASocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED); if (sock_raw == INVALID_SOCKET) { SOCKETDEV_ERROR("WSASocket failed"); break; } unsigned int beginTick = GetTickCount(); //统计时间开始 char icmp_data[MAX_PACKET] = {0}; fill_icmp_data(icmp_data, MAX_PACKET, icmp_id); success = send_icmp_data(sock_raw, ip, icmp_id, try_count, timeout); unsigned int endTick = GetTickCount(); //统计时间结束 if (success) { SOCKETDEV_INFO("Ping [%s] success, use %u ms", ip, (endTick - beginTick) ); } else { SOCKETDEV_ERROR("Ping [%s] failed, use %u ms", ip, (endTick - beginTick)); } } while (0); if (sock_raw != INVALID_SOCKET) { closesocket(sock_raw); } return success; } /*lint +e830*/
相关文章推荐
- C++ 实现 ping 功能&& 域名(URL)解析实际 IP地址
- C++实现ping功能
- C++实现ping功能<转>
- C++实现ping功能
- C++之编码实现ping的功能
- C++ 实现 ping 功能&& 域名(URL)解析实际 IP地址
- C++ 实现 ping 功能&& 域名(URL)解析实际 IP地址
- C++实现Ping功能
- (转载)用C语言实现Ping程序功能
- C++实现顺序栈的基本功能
- C++ 手动实现虚函数功能
- C++ 采集音频流(PCM裸流)实现录音功能
- java实现ping功能
- 用C#实现实现简单的 Ping 的功能,用于测试网络是否已经联通
- 使用swig实现C++的python扩展功能
- MFC使用CEF并实现js与C++交互功能,解决Render进程中OnContextCreated绑定与OnWebKitInitialized的js扩展无法回调问题
- 在linux中用C语言实现ping命令的部分功能
- 用C#实现实现简单的 Ping 的功能,用于测试网络是否已经联通
- (转)C++中虚函数功能的实现机制
- Delphi中实现C++/Java类似静态变量的功能