//头文件 /* * File: CPing.h * Author: jaylong35 * * Created on 2011年1月26日, 下午3:12 */ #ifndef CPING_H #define CPING_H #include <string> #include <signal.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> #include <netdb.h> #include <setjmp.h> #include <errno.h> #include <sys/time.h> using namespace std; #define PACKET_SIZE 4096 #define SEND_DATA_LEN 56 #define ERROR -1 #define SUCCESS 1 #define MAX_WAIT_TIME 5 #define MAX_NO_PACKETS 100 class CPing { public: CPing(const char * ip, int timeout); CPing(const CPing& orig); virtual ~CPing(); private: std::string m_strIp; int m_nTimeOut; int m_nPkgLen; double m_dAvgTime; double m_dFasterResponseTime; double m_dLowerResponseTime; double m_dTotalResponseTimes; int m_nSend; int m_nRecv; int m_nSocketfd; pid_t m_Pid; struct sockaddr_in m_dest_addr; struct sockaddr_in m_from; char m_sendpacket[PACKET_SIZE]; char m_recvpacket[PACKET_SIZE]; struct timeval m_tvrecv; public: enum { PING_FAILED, PING_SUCCEED }; std::string GetIp() { return m_strIp; } int GetTimeOut() { return m_nTimeOut; } int GetPkgLen() { return m_nPkgLen; } void SetIp(const char * ip) { m_strIp = ip; } void SetTimeOut(int timeout) { m_nTimeOut = timeout; } void SetPkgLen(int pkglen) { m_nPkgLen = pkglen; } double GetAvgResponseTime() { return m_dAvgTime; } double GetFasterResponseTime() { return m_dFasterResponseTime; } double GetLowerResponseTime() { return m_dLowerResponseTime; } unsigned int GetPingStatus(); static unsigned short cal_chksum(unsigned short *addr, int len); void statistics(); int pack(int pack_no); void send_packet(int num); void recv_packet(void); int unpack(char *buf, int len); void tv_sub(struct timeval *out, struct timeval *in); bool ping(int times); }; #endif /* CPING_H cpp文件 /* * File: CPing.cpp * Author: jaylong35 * * Created on 2011年1月26日, 下午3:12 */ #include "CPing.h" CPing::CPing(const char * ip, int timeout) { m_strIp = ip; m_nTimeOut = timeout; m_nSend = 0; m_nRecv = 0; m_nSocketfd = 0; } CPing::CPing(const CPing& orig) { } CPing::~CPing() { } bool CPing::ping(int times) { struct hostent *host; struct protoent *protocol; unsigned long inaddr = 0l; int size = 50 * 1024; if ((protocol = getprotobyname("icmp")) == NULL) { perror("getprotobyname"); return false; } /*生成使用ICMP的原始套接字,这种套接字只有root才能生成*/ if ((m_nSocketfd = socket(AF_INET, SOCK_RAW, protocol->p_proto)) < 0) { perror("socket error"); exit(1); } /* 回收root权限,设置当前用户权限*/ setuid(getuid()); /*扩大套接字接收缓冲区到50K这样做主要为了减小接收缓冲区溢出的 的可能性,若无意中ping一个广播地址或多播地址,将会引来大量应答*/ setsockopt(m_nSocketfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)); bzero(&m_dest_addr, sizeof (m_dest_addr)); m_dest_addr.sin_family = AF_INET; /*判断是主机名还是ip地址*/ if (inaddr = inet_addr(m_strIp.c_str()) == INADDR_NONE) { if ((host = gethostbyname(m_strIp.c_str())) == NULL) /*是主机名*/ { perror("gethostbyname error"); exit(1); } memcpy((char *) &m_dest_addr.sin_addr, host->h_addr, host->h_length); } else /*是ip地址*/ memcpy((char *) &m_dest_addr, (char *) &inaddr, host->h_length); /*获取main的进程id,用于设置ICMP的标志符*/ m_Pid = getpid(); printf("PING %s(%s): %d bytes data in ICMP packets./n", m_strIp.c_str(), inet_ntoa(m_dest_addr.sin_addr), SEND_DATA_LEN); int i = 0; while(i < times) { i++; send_packet(1); /*发送所有ICMP报文*/ recv_packet(); /*接收所有ICMP报文*/ } statistics(); /*进行统计*/ } unsigned short CPing::cal_chksum(unsigned short *addr, int len) { int nleft=len; int sum=0; unsigned short *w=addr; unsigned short answer=0; while(nleft > 1) { sum += *w++; nleft -= 2; } if( nleft == 1) { *(unsigned char *)(&answer) = *(unsigned char *)w; sum += answer; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return answer; } void CPing::tv_sub(struct timeval *out,struct timeval *in) { if( (out->tv_usec-=in->tv_usec)<0) {