linux C++ 实现ping类



装载地址:http://blog.csdn.net/jaylong35/article/details/6165306

//头文件

  1. /*  
  2.  * File:   CPing.h 
  3.  * Author: jaylong35 
  4.  * 
  5.  * Created on 2011年1月26日, 下午3:12 
  6.  */  
  7. #ifndef CPING_H  
  8. #define CPING_H  
  9. #include <string>  
  10. #include <signal.h>  
  11. #include <arpa/inet.h>  
  12. #include <sys/types.h>  
  13. #include <sys/socket.h>  
  14. #include <unistd.h>  
  15. #include <netinet/in.h>  
  16. #include <netinet/ip.h>  
  17. #include <netinet/ip_icmp.h>  
  18. #include <netdb.h>  
  19. #include <setjmp.h>  
  20. #include <errno.h>  
  21. #include <sys/time.h>  
  22. using namespace std;  
  23.     
  24. #define PACKET_SIZE     4096  
  25. #define SEND_DATA_LEN   56  
  26. #define ERROR           -1  
  27. #define SUCCESS         1  
  28. #define MAX_WAIT_TIME   5  
  29. #define MAX_NO_PACKETS  100  
  30. class CPing  
  31. {  
  32. public:  
  33.     CPing(const char * ip, int timeout);  
  34.     CPing(const CPing& orig);  
  35.     virtual ~CPing();  
  36. private:  
  37.     std::string m_strIp;  
  38.     int m_nTimeOut;  
  39.     int m_nPkgLen;  
  40.     double m_dAvgTime;  
  41.     double m_dFasterResponseTime;  
  42.     double m_dLowerResponseTime;  
  43.     double m_dTotalResponseTimes;  
  44.     int m_nSend;  
  45.     int m_nRecv;  
  46.     int m_nSocketfd;  
  47.     pid_t m_Pid;  
  48.     struct sockaddr_in m_dest_addr;  
  49.     struct sockaddr_in m_from;  
  50.     char m_sendpacket[PACKET_SIZE];  
  51.     char m_recvpacket[PACKET_SIZE];  
  52.     struct timeval m_tvrecv;  
  53. public:  
  54.     enum  
  55.     {  
  56.         PING_FAILED,  
  57.         PING_SUCCEED  
  58.     };  
  59.     std::string GetIp() { return m_strIp; }  
  60.     int GetTimeOut() { return m_nTimeOut; }  
  61.     int GetPkgLen() { return m_nPkgLen; }  
  62.     void SetIp(const char * ip) { m_strIp = ip; }  
  63.     void SetTimeOut(int timeout) { m_nTimeOut = timeout; }  
  64.     void SetPkgLen(int pkglen) { m_nPkgLen = pkglen; }  
  65.     double GetAvgResponseTime() { return m_dAvgTime; }  
  66.     double GetFasterResponseTime() { return m_dFasterResponseTime; }  
  67.     double GetLowerResponseTime() { return m_dLowerResponseTime; }  
  68.     unsigned int GetPingStatus();  
  69.     static unsigned short cal_chksum(unsigned short *addr, int len);  
  70.     void statistics();  
  71.     int pack(int pack_no);  
  72.     void send_packet(int num);  
  73.     void recv_packet(void);  
  74.     int unpack(char *buf, int len);  
  75.     void tv_sub(struct timeval *out, struct timeval *in);  
  76.     bool ping(int times);  
  77. };  
  78. #endif  /* CPING_H   


 

cpp文件

  1. /*  
  2.  * File:   CPing.cpp 
  3.  * Author: jaylong35 
  4.  *  
  5.  * Created on 2011年1月26日, 下午3:12 
  6.  */  
  7. #include "CPing.h"  
  8. CPing::CPing(const char * ip, int timeout)  
  9. {  
  10.     m_strIp = ip;  
  11.     m_nTimeOut = timeout;  
  12.     m_nSend = 0;  
  13.     m_nRecv = 0;  
  14.     m_nSocketfd = 0;  
  15. }  
  16. CPing::CPing(const CPing& orig)  
  17. {  
  18. }  
  19. CPing::~CPing()  
  20. {  
  21. }  
  22. bool CPing::ping(int times)  
  23. {  
  24.     struct hostent *host;  
  25.     struct protoent *protocol;  
  26.     unsigned long inaddr = 0l;  
  27.     int size = 50 * 1024;  
  28.     if ((protocol = getprotobyname("icmp")) == NULL)  
  29.     {  
  30.         perror("getprotobyname");  
  31.         return false;  
  32.     }  
  33.     /*生成使用ICMP的原始套接字,这种套接字只有root才能生成*/  
  34.     if ((m_nSocketfd = socket(AF_INET, SOCK_RAW, protocol->p_proto)) < 0)  
  35.     {  
  36.         perror("socket error");  
  37.         exit(1);  
  38.     }  
  39.     /* 回收root权限,设置当前用户权限*/  
  40.     setuid(getuid());  
  41.     /*扩大套接字接收缓冲区到50K这样做主要为了减小接收缓冲区溢出的 
  42.       的可能性,若无意中ping一个广播地址或多播地址,将会引来大量应答*/  
  43.     setsockopt(m_nSocketfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size));  
  44.     bzero(&m_dest_addr, sizeof (m_dest_addr));  
  45.     m_dest_addr.sin_family = AF_INET;  
  46.     /*判断是主机名还是ip地址*/  
  47.     if (inaddr = inet_addr(m_strIp.c_str()) == INADDR_NONE)  
  48.     {  
  49.         if ((host = gethostbyname(m_strIp.c_str())) == NULL) /*是主机名*/  
  50.         {  
  51.             perror("gethostbyname error");  
  52.             exit(1);  
  53.         }  
  54.         memcpy((char *) &m_dest_addr.sin_addr, host->h_addr, host->h_length);  
  55.     }  
  56.     else /*是ip地址*/  
  57.         memcpy((char *) &m_dest_addr, (char *) &inaddr, host->h_length);  
  58.     /*获取main的进程id,用于设置ICMP的标志符*/  
  59.     m_Pid = getpid();  
  60.     printf("PING %s(%s): %d bytes data in ICMP packets./n", m_strIp.c_str(),  
  61.             inet_ntoa(m_dest_addr.sin_addr), SEND_DATA_LEN);  
  62.     int i = 0;  
  63.     while(i < times)  
  64.     {  
  65.         i++;  
  66.         send_packet(1); /*发送所有ICMP报文*/  
  67.         recv_packet(); /*接收所有ICMP报文*/  
  68.     }  
  69.     statistics(); /*进行统计*/  
  70. }  
  71. unsigned short CPing::cal_chksum(unsigned short *addr, int len)  
  72. {  
  73.     int nleft=len;  
  74.     int sum=0;  
  75.     unsigned short *w=addr;  
  76.     unsigned short answer=0;  
  77.     while(nleft > 1)  
  78.     {  
  79.         sum += *w++;  
  80.         nleft -= 2;  
  81.     }  
  82.     if( nleft == 1)  
  83.     {  
  84.         *(unsigned char *)(&answer) = *(unsigned char *)w;  
  85.         sum += answer;  
  86.     }  
  87.     sum = (sum >> 16) + (sum & 0xffff);  
  88.     sum += (sum >> 16);  
  89.     answer = ~sum;  
  90.     return answer;  
  91. }  
  92. void CPing::tv_sub(struct timeval *out,struct timeval *in)  
  93. {         
  94.     if( (out->tv_usec-=in->tv_usec)<0)  
  95.     {         
  96.         --out->tv_sec;  
  97.         out->tv_usec+=1000000;  
  98.     }  
  99.     out->tv_sec-=in->tv_sec;  
  100. }  
  101. void CPing::statistics()  
  102. {  
  103.     printf("/n--------------------PING statistics-------------------/n");  
  104.     printf("%d packets transmitted, %d received , %%%d lost/n", m_nSend, m_nRecv,  
  105.             (m_nSend - m_nRecv) / m_nSend * 100);  
  106.     close(m_nSocketfd);  
  107.     m_nTimeOut = m_nSend - m_nRecv;  
  108.     m_dAvgTime = m_dTotalResponseTimes/m_nRecv;  
  109.     return;  
  110. }  
  111. /*设置ICMP报头*/  
  112. int CPing::pack(int pack_no)  
  113. {  
  114.     int packsize;  
  115.     struct icmp *icmp;  
  116.     struct timeval *tval;  
  117.     icmp = (struct icmp*) m_sendpacket;  
  118.     icmp->icmp_type = ICMP_ECHO;  
  119.     icmp->icmp_code = 0;  
  120.     icmp->icmp_cksum = 0;  
  121.     icmp->icmp_seq = pack_no;  
  122.     icmp->icmp_id = m_Pid;  
  123.     packsize = 8 + SEND_DATA_LEN;  
  124.     tval = (struct timeval *) icmp->icmp_data;  
  125.     gettimeofday(tval, NULL); /*记录发送时间*/  
  126.     icmp->icmp_cksum = cal_chksum((unsigned short *) icmp, packsize); /*校验算法*/  
  127.     return packsize;  
  128. }  
  129. /*发送三个ICMP报文*/  
  130. void CPing::send_packet(int num)  
  131. {  
  132.     if(num > MAX_NO_PACKETS)  
  133.         num = MAX_NO_PACKETS;  
  134.     int packetsize;  
  135.     int i = 0;  
  136.     while (i < num)  
  137.     {  
  138.         i++;  
  139.         m_nSend++;  
  140.         packetsize = pack(m_nSend); /*设置ICMP报头*/  
  141.         if (sendto(m_nSocketfd, m_sendpacket, packetsize, 0,  
  142.                 (struct sockaddr *) &m_dest_addr, sizeof (m_dest_addr)) < 0)  
  143.         {  
  144.             perror("sendto error");  
  145.             continue;  
  146.         }  
  147.         sleep(1); /*每隔一秒发送一个ICMP报文*/  
  148.     }  
  149. }  
  150. /*接收所有ICMP报文*/  
  151. void CPing::recv_packet()  
  152. {  
  153.     int n,fromlen;  
  154.     //signal(SIGALRM, statistics);  
  155.     fromlen = sizeof (m_from);  
  156.     while (m_nRecv < m_nSend)  
  157.     {  
  158.         alarm(MAX_WAIT_TIME);  
  159.         if ((n = recvfrom(m_nSocketfd, m_recvpacket, sizeof (m_recvpacket), 0,  
  160.                 (struct sockaddr *) &m_from, (socklen_t *)&fromlen)) < 0)  
  161.         {  
  162.             if (errno == EINTR)continue;  
  163.             perror("recvfrom error");  
  164.             continue;  
  165.         }  
  166.         gettimeofday(&m_tvrecv, NULL); /*记录接收时间*/  
  167.         if (unpack(m_recvpacket, n) == -1)  
  168.             continue;  
  169.         m_nRecv++;  
  170.     }  
  171. }  
  172. /*剥去ICMP报头*/  
  173. int CPing::unpack(char *buf,int len)  
  174. {  
  175.     int i,iphdrlen;  
  176.     struct ip *ip;  
  177.     struct icmp *icmp;  
  178.     struct timeval *tvsend;  
  179.     double rtt;  
  180.     ip = (struct ip *) buf;  
  181.     iphdrlen = ip->ip_hl << 2; /*求ip报头长度,即ip报头的长度标志乘4*/  
  182.     icmp = (struct icmp *) (buf + iphdrlen); /*越过ip报头,指向ICMP报头*/  
  183.     len -= iphdrlen; /*ICMP报头及ICMP数据报的总长度*/  
  184.     if (len < 8) /*小于ICMP报头长度则不合理*/  
  185.     {  
  186.         printf("ICMP packets/'s length is less than 8/n");  
  187.         return -1;  
  188.     }  
  189.     /*确保所接收的是我所发的的ICMP的回应*/  
  190.     if ((icmp->icmp_type == ICMP_ECHOREPLY) && (icmp->icmp_id == m_Pid))  
  191.     {  
  192.         tvsend = (struct timeval *) icmp->icmp_data;  
  193.         tv_sub(&m_tvrecv, tvsend); /*接收和发送的时间差*/  
  194.         rtt = m_tvrecv.tv_sec * 1000 + m_tvrecv.tv_usec / 1000; /*以毫秒为单位计算rtt*/  
  195.         m_dTotalResponseTimes += rtt;  
  196.         if(m_dFasterResponseTime == -1)  
  197.         {  
  198.             m_dFasterResponseTime = rtt;  
  199.         }  
  200.         else if(m_dFasterResponseTime > rtt)  
  201.         {  
  202.             m_dFasterResponseTime = rtt;  
  203.         }  
  204.         if(m_dLowerResponseTime == -1)  
  205.         {  
  206.             m_dLowerResponseTime = rtt;  
  207.         }  
  208.         else if(m_dLowerResponseTime < rtt)  
  209.         {  
  210.             m_dLowerResponseTime = rtt;  
  211.         }  
  212.         /*显示相关信息*/  
  213.         printf("%d/tbyte from %s/t: icmp_seq=%u/tttl=%d/trtt=%.3f/tms/n",  
  214.                 len,  
  215.                 inet_ntoa(m_from.sin_addr),  
  216.                 icmp->icmp_seq,  
  217.                 ip->ip_ttl,  
  218.                 rtt);  
  219.     }  
  220.     else return -1;  
  221. }  


 

调用 

  1. #include "CPing.h"  
  2. int main()  
  3. {  
  4.     CPing ping("192.168.10.48",100);  
  5.     ping.ping(20);  
  6. }  


 
运行结果

PING 192.168.10.48(0.0.0.0): 56 bytes data in ICMP packets.表明          
64      byte from 127.0.0.1     : icmp_seq=1    ttl=64  rtt=1000.000    ms
64      byte from 127.0.0.1     : icmp_seq=2    ttl=64  rtt=1001.000    ms
64      byte from 127.0.0.1     : icmp_seq=3    ttl=64  rtt=1001.000    ms
64      byte from 127.0.0.1     : icmp_seq=4    ttl=64  rtt=1001.000    ms
64      byte from 127.0.0.1     : icmp_seq=5    ttl=64  rtt=1001.000    ms
64      byte from 127.0.0.1     : icmp_seq=6    ttl=64  rtt=1002.000    ms
64      byte from 127.0.0.1     : icmp_seq=7    ttl=64  rtt=1001.000    ms
64      byte from 127.0.0.1     : icmp_seq=8    ttl=64  rtt=1002.000    ms
64      byte from 127.0.0.1     : icmp_seq=9    ttl=64  rtt=1002.000    ms
64      byte from 127.0.0.1     : icmp_seq=10   ttl=64  rtt=1000.000    ms
64      byte from 127.0.0.1     : icmp_seq=11   ttl=64  rtt=1001.000    ms
64      byte from 127.0.0.1     : icmp_seq=12   ttl=64  rtt=1001.000    ms
64      byte from 127.0.0.1     : icmp_seq=13   ttl=64  rtt=1001.000    ms
64      byte from 127.0.0.1     : icmp_seq=14   ttl=64  rtt=1000.000    ms
64      byte from 127.0.0.1     : icmp_seq=15   ttl=64  rtt=1001.000    ms
64      byte from 127.0.0.1     : icmp_seq=16   ttl=64  rtt=1001.000    ms
64      byte from 127.0.0.1     : icmp_seq=17   ttl=64  rtt=1001.000    ms
64      byte from 127.0.0.1     : icmp_seq=18   ttl=64  rtt=1002.000    ms
64      byte from 127.0.0.1     : icmp_seq=19   ttl=64  rtt=1001.000    ms
64      byte from 127.0.0.1     : icmp_seq=20   ttl=64  rtt=1001.000    ms
                                                                                                                 
--------------------PING statistics-------------------                                         
20 packets transmitted, 20 received , %0 lost                                         
按 [Enter] 键关闭终端...                                                                              


更新最新可用版本

因为很多朋友都要一个可用版本,所以今天在这里更新一下上面的程序

新版本的程序如下

.h

  1. /*  
  2.  * File:   CPing.h 
  3.  * Author: scotte.ye 
  4.  * 
  5.  * Created on 2011年1月26日, 下午3:12 
  6.  */  
  7.   
  8. #ifndef CPING_H  
  9. #define CPING_H  
  10. #include <string>  
  11. #include <signal.h>  
  12. #include <arpa/inet.h>  
  13. #include <sys/types.h>  
  14. #include <sys/socket.h>  
  15. #include <unistd.h>  
  16. #include <netinet/in.h>  
  17. #include <netinet/ip.h>  
  18. #include <netinet/ip_icmp.h>  
  19. #include <netdb.h>  
  20. #include <setjmp.h>  
  21. #include <errno.h>  
  22. #include <sys/time.h>  
  23. using namespace std;  
  24.   
  25.     
  26. #define PACKET_SIZE     4096  
  27. #define SEND_DATA_LEN   56  
  28. #define ERROR           -1  
  29. #define SUCCESS         1  
  30. #define MAX_WAIT_TIME  20  
  31. #define MAX_NO_PACKETS  4  
  32.   
  33. class CPing  
  34. {  
  35. public:  
  36.     CPing(const char * ip, int timeout);  
  37.     CPing(const CPing& orig);  
  38.     virtual ~CPing();  
  39. private:  
  40.     std::string m_strIp;  
  41.     std::string m_Ip;  
  42.     int m_nTimeOut;  
  43.     int m_nPkgLen;  
  44.     double m_dAvgTime;  
  45.     double m_dFasterResponseTime;  
  46.     double m_dLowerResponseTime;  
  47.     double m_dTotalResponseTimes;  
  48.     int m_nSend;  
  49.     int m_nRecv;  
  50.     int m_nSocketfd;  
  51.     pid_t m_Pid;  
  52.     struct sockaddr_in m_dest_addr;  
  53.     struct sockaddr_in m_from;  
  54.     char m_sendpacket[PACKET_SIZE];  
  55.     char m_recvpacket[PACKET_SIZE];  
  56.     struct timeval m_tvrecv;  
  57.   
  58.     bool m_bTimeOut;  
  59.   
  60.     //add by scotte.ye 2011-07-27  
  61.     int m_nMaxTimeWait;  
  62.     int m_nMaxTestpkg;  
  63. public:  
  64.     enum  
  65.     {  
  66.         PING_FAILED,  
  67.         PING_SUCCEED  
  68.     };  
  69.   
  70.     void SetMaxTimeWait(int nMaxTimeWait) { m_nMaxTimeWait = nMaxTimeWait; }  
  71.     void SetMaxTestpkg(int nMaxTestpkg) { m_nMaxTestpkg = nMaxTestpkg; }  
  72.   
  73.     void SetPingManager(CPingManager * pPingManager) { m_pPingManager = pPingManager; }  
  74.   
  75.     int GetSuccessTimes() { return m_nRecv; }  
  76.     std::string GetIp() { return m_Ip; }  
  77.     int GetTimeOut() { return m_nTimeOut; }  
  78.     int GetPkgLen() { return m_nPkgLen; }  
  79.   
  80.     void SetIp(const char * ip) { m_strIp = ip; }  
  81.     void SetTimeOut(int timeout) { m_nTimeOut = timeout; }  
  82.     void SetPkgLen(int pkglen) { m_nPkgLen = pkglen; }  
  83.   
  84.     double GetAvgResponseTime() { return m_dAvgTime; }  
  85.     double GetFasterResponseTime() { return m_dFasterResponseTime; }  
  86.     double GetLowerResponseTime() { return m_dLowerResponseTime; }  
  87.     unsigned int GetPingStatus();  
  88.   
  89.     static unsigned short cal_chksum(unsigned short *addr, int len);  
  90.     //void statistics(int sig);  
  91.     int pack(int pack_no);  
  92.     void send_packet(void);  
  93.     void recv_packet(void);  
  94.     int unpack(char *buf, int len);  
  95.     void tv_sub(struct timeval *out, struct timeval *in);  
  96.   
  97.     bool ping(int times);  
  98.     void statistics(int sig);  
  99.   
  100.     bool CreateSocket();  
  101.     bool CloseSocket();  
  102.     //double ping_m();  
  103. };  
  104.   
  105. #endif  /* CPING_H */  
/* 
 * File:   CPing.h
 * Author: scotte.ye
 *
 * 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  20
#define MAX_NO_PACKETS  4

class CPing
{
public:
    CPing(const char * ip, int timeout);
    CPing(const CPing& orig);
    virtual ~CPing();
private:
    std::string m_strIp;
    std::string m_Ip;
    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;

    bool m_bTimeOut;

    //add by scotte.ye 2011-07-27
    int m_nMaxTimeWait;
    int m_nMaxTestpkg;
public:
    enum
    {
        PING_FAILED,
        PING_SUCCEED
    };

    void SetMaxTimeWait(int nMaxTimeWait) { m_nMaxTimeWait = nMaxTimeWait; }
    void SetMaxTestpkg(int nMaxTestpkg) { m_nMaxTestpkg = nMaxTestpkg; }

    void SetPingManager(CPingManager * pPingManager) { m_pPingManager = pPingManager; }

    int GetSuccessTimes() { return m_nRecv; }
    std::string GetIp() { return m_Ip; }
    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 sig);
    int pack(int pack_no);
    void send_packet(void);
    void recv_packet(void);
    int unpack(char *buf, int len);
    void tv_sub(struct timeval *out, struct timeval *in);

    bool ping(int times);
    void statistics(int sig);

    bool CreateSocket();
    bool CloseSocket();
    //double ping_m();
};

#endif	/* CPING_H */


cpp

  1. /*  
  2.  * File:   CPing.cpp 
  3.  * Author: scotte.ye 
  4.  *  
  5.  * Created on 2011年1月26日, 下午3:12 
  6.  */  
  7.   
  8. #include "CPing.h"  
  9. #include "CPingManager.h"  
  10. #include "include/Log/CLog.h"  
  11. #include <sys/types.h>  
  12. #include <fcntl.h>  
  13. #define gettid() syscall(224)  
  14.   
  15. void CPing::statistics(int sig)  
  16. {  
  17.     printf("------statistics------\n");  
  18.     printf("%d packets transmitted, %d received , %%%d lost\n", m_nSend, m_nRecv,  
  19.             (m_nSend - m_nRecv) / m_nSend * 100);  
  20.     //close(m_nSocketfd);  
  21.     m_nTimeOut = m_nSend - m_nRecv;  
  22.     m_dAvgTime = m_dTotalResponseTimes/m_nRecv;  
  23.    // m_bTimeOut = true;  
  24. }  
  25.   
  26. CPing::CPing(const char * ip, int timeout)  
  27. {  
  28.     m_strIp = ip;  
  29.     m_Ip = ip;  
  30.     m_nTimeOut = 0;  
  31.     m_nSend = 0;  
  32.     m_nRecv = 0;  
  33.     m_nSocketfd = 0;  
  34.     m_dFasterResponseTime = -1;  
  35.     m_dLowerResponseTime = -1;  
  36.     m_dAvgTime = -1;  
  37.     m_dTotalResponseTimes = 0;  
  38.     m_pPingManager = NULL;  
  39.     if(timeout > MAX_WAIT_TIME)  
  40.         m_nMaxTimeWait = MAX_WAIT_TIME;  
  41.     else  
  42.         m_nMaxTimeWait = timeout;  
  43.   
  44.     m_nMaxTestpkg = MAX_NO_PACKETS;  
  45. }  
  46.   
  47. CPing::CPing(const CPing& orig)  
  48. {  
  49. }  
  50.   
  51. CPing::~CPing()  
  52. {  
  53.     CloseSocket();  
  54. }  
  55.   
  56. bool CPing::CreateSocket()  
  57. {  
  58.     CloseSocket();  
  59.     struct hostent hostinfo,*host;  
  60.     char buf[2048];  
  61.     struct protoent *protocol;  
  62.     unsigned long inaddr = 0l;  
  63.     int size = 50 * 1024;  
  64.   
  65.     if ((protocol = getprotobyname("icmp")) == NULL)  
  66.     {  
  67.         printf("CreateSocket: getprotobyname failed:%d\n",errno);  
  68.           
  69.           
  70.         return false;  
  71.     }  
  72.   
  73.     /*生成使用ICMP的原始套接字,这种套接字只有root才能生成*/  
  74.     if ((m_nSocketfd = socket(AF_INET, SOCK_RAW, protocol->p_proto)) < 0)  
  75.     {  
  76.         printf("CreateSocket: create socket failed:%d\n",errno);  
  77.           
  78.           
  79.         return false;  
  80.     }  
  81.   
  82.     /* 回收root权限,设置当前用户权限*/  
  83.     setuid(getuid());  
  84.   
  85.     /*扩大套接字接收缓冲区到50K这样做主要为了减小接收缓冲区溢出的 
  86.       的可能性,若无意中ping一个广播地址或多播地址,将会引来大量应答*/  
  87.     int nRet = setsockopt(m_nSocketfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size));  
  88.     if(nRet != 0)  
  89.     {          
  90.         printf("CreateSocket: set socket receive buf failed:%d\n",errno);  
  91.           
  92.         return false;  
  93.           
  94.     }  
  95.     bzero(&m_dest_addr, sizeof (m_dest_addr));  
  96.     m_dest_addr.sin_family = AF_INET;  
  97.   
  98.     /*判断是主机名还是ip地址*/  
  99.     if ((inaddr = inet_addr(m_strIp.c_str())) == INADDR_NONE)  
  100.     {  
  101.         int nret;  
  102.         gethostbyname_r(m_strIp.c_str(), &hostinfo, buf, sizeof(buf), &host, &nret);  
  103.         if (nret != 0) /*是主机名*/  
  104.         {  
  105.             printf("CreateSocket: gethostbyname error %s failed:%d\n",m_strIp.c_str(),errno);  
  106.               
  107.             return false;  
  108.           
  109.         }  
  110.         memcpy((char *) &m_dest_addr.sin_addr, host->h_addr, host->h_length);  
  111.     }  
  112.     else /*是ip地址*/  
  113.         memcpy((char *) &m_dest_addr.sin_addr, (char *) &inaddr, sizeof(inaddr));  
  114.   
  115.     m_Ip = inet_ntoa(m_dest_addr.sin_addr);  
  116.     return true;  
  117. }  
  118.   
  119. bool CPing::CloseSocket()  
  120. {  
  121.     if(m_nSocketfd !=0)  
  122.         close(m_nSocketfd);  
  123.     m_nSocketfd = 0;  
  124.     return true;  
  125. }  
  126.   
  127. bool CPing::ping(int times)  
  128. {  
  129.     int i = 0;  
  130.     while(i < times)  
  131.     {  
  132.         bool bRet = CreateSocket();  
  133.         if(!bRet)  
  134.         {  
  135.             printf("ping: create socket falied!\n");  
  136.               
  137.   
  138.             return false;  
  139.         }  
  140.   
  141.         /*获取main的进程id,用于设置ICMP的标志符*/  
  142.         int nh = gettid();  
  143.         nh = nh<<8;  
  144.         time_t t;  
  145.         time(&t);  
  146.         int nt = t;  
  147.         nh = nh&0xff00;  
  148.         nt = nt&0xff;  
  149.         m_Pid = nt|nh;  
  150.         printf("PING %s(%s): %d bytes data in ICMP packets.\n", m_strIp.c_str(),  
  151.                 m_Ip.c_str(), SEND_DATA_LEN);  
  152.         i++;  
  153.         m_nSend = 0;  
  154.         m_nRecv = 0;  
  155.         send_packet(); /*发送所有ICMP报文*/  
  156.         recv_packet(); /*接收所有ICMP报文*/  
  157.         //statistics(SIGALRM); /*进行统计*/  
  158.         if(m_nRecv > 0)  
  159.             break;  
  160.     }  
  161.     m_bTimeOut = false;  
  162.     if(m_nRecv > 0)  
  163.     {  
  164.         m_nTimeOut = m_nSend - m_nRecv;  
  165.         m_dAvgTime = m_dTotalResponseTimes/m_nRecv;  
  166.     }  
  167.     else  
  168.     {  
  169.         m_nTimeOut = m_nSend;  
  170.         m_dAvgTime = -1;  
  171.         return false;  
  172.     }  
  173.     return true;  
  174. }  
  175.   
  176. unsigned short CPing::cal_chksum(unsigned short *addr, int len)  
  177. {  
  178.     int nleft=len;  
  179.     int sum=0;  
  180.     unsigned short *w=addr;  
  181.     unsigned short answer=0;  
  182.   
  183.     while(nleft > 1)  
  184.     {  
  185.         sum += *w++;  
  186.         nleft -= 2;  
  187.     }  
  188.   
  189.     if( nleft == 1)  
  190.     {  
  191.         *(unsigned char *)(&answer) = *(unsigned char *)w;  
  192.         sum += answer;  
  193.     }  
  194.   
  195.     sum = (sum >> 16) + (sum & 0xffff);  
  196.     sum += (sum >> 16);  
  197.     answer = ~sum;  
  198.   
  199.     return answer;  
  200. }  
  201.   
  202.   
  203. void CPing::tv_sub(struct timeval *out,struct timeval *in)  
  204. {         
  205.     if( (out->tv_usec-=in->tv_usec)<0)  
  206.     {         
  207.         --out->tv_sec;  
  208.         out->tv_usec+=1000000;  
  209.     }  
  210.     out->tv_sec-=in->tv_sec;  
  211. }  
  212.   
  213. /*设置ICMP报头*/  
  214. int CPing::pack(int pack_no)  
  215. {  
  216.     int packsize;  
  217.     struct icmp *icmp;  
  218.     struct timeval *tval;  
  219.   
  220.     icmp = (struct icmp*) m_sendpacket;  
  221.     icmp->icmp_type = ICMP_ECHO;  
  222.     icmp->icmp_code = 0;  
  223.     icmp->icmp_cksum = 0;  
  224.     icmp->icmp_seq = pack_no;  
  225.     icmp->icmp_id = m_Pid;  
  226.     packsize = 8 + SEND_DATA_LEN;  
  227.     tval = (struct timeval *) icmp->icmp_data;  
  228.     gettimeofday(tval, NULL); /*记录发送时间*/  
  229.     icmp->icmp_cksum = cal_chksum((unsigned short *) icmp, packsize); /*校验算法*/  
  230.     return packsize;  
  231. }  
  232.   
  233. /*发送三个ICMP报文*/  
  234. void CPing::send_packet()  
  235. {  
  236.     int packetsize;  
  237.     while (m_nSend < m_nMaxTestpkg)  
  238.     {  
  239.         m_nSend++;  
  240.         packetsize = pack(m_nSend); /*设置ICMP报头*/  
  241.         if (sendto(m_nSocketfd, m_sendpacket, packetsize, 0,  
  242.                 (struct sockaddr *) &m_dest_addr, sizeof (m_dest_addr)) < 0)  
  243.         {  
  244.             printf("send_packet: send error :%d\n",errno);  
  245.               
  246.             continue;  
  247.         }  
  248.         usleep(2); /*每隔一秒发送一个ICMP报文*/  
  249.     }  
  250. }  
  251.   
  252. /*接收所有ICMP报文*/  
  253. void CPing::recv_packet()  
  254. {  
  255.     int n,fromlen;  
  256.   
  257.     
  258.     while(m_nRecv < m_nSend)  
  259.     {  
  260.         struct timeval timeo;  
  261.         fd_set readfds;  
  262.         FD_ZERO(&readfds);  
  263.         FD_SET(m_nSocketfd,&readfds);  
  264.         int maxfds = m_nSocketfd +1;  
  265.         timeo.tv_sec = m_nMaxTimeWait;  
  266.         timeo.tv_usec = 0;  
  267.   
  268.         n = select(maxfds,&readfds,NULL,NULL,&timeo);  
  269.         if(n == 0)  
  270.         {  
  271.             printf("recv_packet: select time out :%d",errno);  
  272.               
  273.             return ;  
  274.         }  
  275.         else if(n < 0)  
  276.         {  
  277.             printf("recv_packet: select error :%d",errno);  
  278.               
  279.             if(errno == EINTR)  
  280.             {  
  281.                 printf("recv_packet: select error :%d",errno);  
  282.                   
  283.                 continue;  
  284.             }  
  285.             else  
  286.             {  
  287.                 printf("recv_packet: select error :%d",errno);  
  288.                   
  289.                 return ;  
  290.             }  
  291.         }  
  292.         if ((n = recvfrom(m_nSocketfd, m_recvpacket, sizeof (m_recvpacket), 0,  
  293.                     (struct sockaddr *) &m_from, (socklen_t *)&fromlen)) <= 0)  
  294.         {  
  295.             printf("recv_packet: recv error :%d",errno);  
  296.               
  297.             return;  
  298.         }  
  299.         gettimeofday(&m_tvrecv, NULL); /*记录接收时间*/  
  300.         if (unpack(m_recvpacket, n) == -1)  
  301.         {  
  302.             continue;  
  303.         }  
  304.             m_nRecv++;  
  305.     }  
  306.     //return ;  
  307. }  
  308. /*剥去ICMP报头*/  
  309. int CPing::unpack(char *buf,int len)  
  310. {  
  311.     int i,iphdrlen;  
  312.     struct ip *ip;  
  313.     struct icmp *icmp;  
  314.     struct timeval *tvsend;  
  315.     double rtt;  
  316.   
  317.     ip = (struct ip *) buf;  
  318.     iphdrlen = ip->ip_hl << 2; /*求ip报头长度,即ip报头的长度标志乘4*/  
  319.     icmp = (struct icmp *) (buf + iphdrlen); /*越过ip报头,指向ICMP报头*/  
  320.     len -= iphdrlen; /*ICMP报头及ICMP数据报的总长度*/  
  321.     if (len < 8) /*小于ICMP报头长度则不合理*/  
  322.     {  
  323.         printf( "ICMP packets\'s length is less than 8");  
  324.           
  325.         return -1;  
  326.     }  
  327.     /*确保所接收的是我所发的的ICMP的回应*/  
  328.     if ((icmp->icmp_type == ICMP_ECHOREPLY) && (icmp->icmp_id == m_Pid)&&(m_Ip == inet_ntoa(m_from.sin_addr)))  
  329.     {  
  330.         tvsend = (struct timeval *) icmp->icmp_data;  
  331.         tv_sub(&m_tvrecv, tvsend); /*接收和发送的时间差*/  
  332.         rtt = m_tvrecv.tv_sec * 1000 + m_tvrecv.tv_usec / 1000; /*以毫秒为单位计算rtt*/  
  333.         m_dTotalResponseTimes += rtt;  
  334.         if(m_dFasterResponseTime == -1)  
  335.         {  
  336.             m_dFasterResponseTime = rtt;  
  337.         }  
  338.         else if(m_dFasterResponseTime > rtt)  
  339.         {  
  340.             m_dFasterResponseTime = rtt;  
  341.         }  
  342.   
  343.         if(m_dLowerResponseTime == -1)  
  344.         {  
  345.             m_dLowerResponseTime = rtt;  
  346.         }  
  347.         else if(m_dLowerResponseTime < rtt)  
  348.         {  
  349.             m_dLowerResponseTime = rtt;  
  350.         }  
  351.   
  352.         /*显示相关信息*/  
  353.         printf("%d\tbyte from %s\t: icmp_seq=%u\tttl=%d\trtt=%.3f\tms\n",  
  354.                 len,  
  355.                 inet_ntoa(m_from.sin_addr),  
  356.                 icmp->icmp_seq,  
  357.                 ip->ip_ttl,  
  358.                 rtt);  
  359.     }  
  360.     else  
  361.     {  
  362.        printf("throw away the old package %d\tbyte from %s\t: icmp_seq=%u\tttl=%d\trtt=%.3f\tms",  
  363.                 len,  
  364.                 inet_ntoa(m_from.sin_addr),  
  365.                 icmp->icmp_seq,  
  366.                 ip->ip_ttl,  
  367.                 rtt);  
  368.           
  369.         return -1;  
  370.     }  
  371. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值