MyPingip.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. #include "MyPingip.h"
  2. #include <iostream>
  3. #include <cstdlib>
  4. #include <netdb.h>
  5. #include <sys/select.h>
  6. CMyPingip::CMyPingip(void) : m_sockfd(-1)
  7. {
  8. }
  9. CMyPingip::~CMyPingip(void)
  10. {
  11. if (m_sockfd != -1) {
  12. close(m_sockfd);
  13. }
  14. }
  15. long CMyPingip::GetTickCount()
  16. {
  17. struct timeval tv;
  18. gettimeofday(&tv, NULL);
  19. return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
  20. }
  21. bool CMyPingip::PingFunction(const char* pstrHost)
  22. {
  23. unsigned int nRetries = 5;
  24. int nLostConnectCnt = 0;
  25. bool bRet = true;
  26. // 创建原始套接字
  27. m_sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
  28. if (m_sockfd < 0) {
  29. std::cerr << "Create Socket Error: " << strerror(errno) << std::endl;
  30. return false;
  31. }
  32. // 设置超时选项
  33. struct timeval timeout;
  34. timeout.tv_sec = 1;
  35. timeout.tv_usec = 0;
  36. setsockopt(m_sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
  37. struct sockaddr_in saDest;
  38. struct hostent* host;
  39. // 解析主机名
  40. if (host = gethostbyname(pstrHost)) {
  41. memcpy(&saDest.sin_addr, host->h_addr, host->h_length);
  42. }
  43. else {
  44. std::cerr << "Hostname resolution failed: " << pstrHost << std::endl;
  45. close(m_sockfd);
  46. return false;
  47. }
  48. saDest.sin_family = AF_INET;
  49. saDest.sin_port = 0;
  50. // ping 循环
  51. for (unsigned int nLoop = 0; nLoop < nRetries; nLoop++) {
  52. // 发送ICMP回应请求
  53. if (SendEchoRequest(m_sockfd, &saDest) < 0) {
  54. nLostConnectCnt++;
  55. continue;
  56. }
  57. // 等待回应
  58. if (WaitForEchoReply(m_sockfd)) {
  59. struct sockaddr_in saSrc;
  60. u_char cTTL;
  61. // 获取回应
  62. long dwTimeSent = RecvEchoReply(m_sockfd, &saSrc, &cTTL);
  63. if (dwTimeSent > 0) {
  64. char* strIp = inet_ntoa(saSrc.sin_addr);
  65. if (strcmp(strIp, pstrHost) == 0) {
  66. long dwElapsed = GetTickCount() - dwTimeSent;
  67. std::cout << "Reply from: " << strIp
  68. << ": bytes=" << REQ_DATASIZE
  69. << " time=" << dwElapsed << " ms"
  70. << " TTL=" << static_cast<int>(cTTL) << std::endl;
  71. }
  72. else {
  73. std::cout << "Reply from: " << strIp
  74. << ": Destination host unreachable" << std::endl;
  75. nLostConnectCnt++;
  76. }
  77. }
  78. else {
  79. nLostConnectCnt++;
  80. }
  81. }
  82. else {
  83. std::cout << "Request Timed Out" << std::endl;
  84. nLostConnectCnt++;
  85. }
  86. }
  87. close(m_sockfd);
  88. m_sockfd = -1;
  89. return (nLostConnectCnt < 3);
  90. }
  91. int CMyPingip::SendEchoRequest(int sock, struct sockaddr_in* dest_addr)
  92. {
  93. static ECHOREQUEST echo;
  94. static int nId = 1;
  95. static int nSeq = 1;
  96. // 填充ICMP头
  97. echo.icmpHdr.Type = ICMP_ECHO;
  98. echo.icmpHdr.Code = 0;
  99. echo.icmpHdr.Checksum = 0;
  100. echo.icmpHdr.ID = htons(nId++);
  101. echo.icmpHdr.Seq = htons(nSeq++);
  102. // 填充数据
  103. for (int i = 0; i < REQ_DATASIZE; i++) {
  104. echo.cData[i] = ' ' + i;
  105. }
  106. // 保存发送时间
  107. echo.dwTime = GetTickCount();
  108. // 计算校验和
  109. echo.icmpHdr.Checksum = in_cksum((unsigned short*)&echo, sizeof(ECHOREQUEST));
  110. // 发送请求
  111. int nRet = sendto(sock, &echo, sizeof(ECHOREQUEST), 0,
  112. (struct sockaddr*)dest_addr, sizeof(struct sockaddr_in));
  113. if (nRet < 0) {
  114. std::cerr << "Send error: " << strerror(errno) << std::endl;
  115. }
  116. return nRet;
  117. }
  118. long CMyPingip::RecvEchoReply(int sock, struct sockaddr_in* from_addr, u_char* pTTL)
  119. {
  120. ECHOREPLY echoReply;
  121. socklen_t from_len = sizeof(struct sockaddr_in);
  122. // 接收回应
  123. int nRet = recvfrom(sock, &echoReply, sizeof(ECHOREPLY), 0,
  124. (struct sockaddr*)from_addr, &from_len);
  125. if (nRet < 0) {
  126. if (errno != EAGAIN && errno != EWOULDBLOCK) {
  127. std::cerr << "Receive error: " << strerror(errno) << std::endl;
  128. }
  129. return -1;
  130. }
  131. // 获取TTL值
  132. *pTTL = echoReply.iphdr.TTL;
  133. // 返回发送时间
  134. return echoReply.echorequest.dwTime;
  135. }
  136. int CMyPingip::WaitForEchoReply(int sock)
  137. {
  138. fd_set readfds;
  139. FD_ZERO(&readfds);
  140. FD_SET(sock, &readfds);
  141. struct timeval timeout;
  142. timeout.tv_sec = 1;
  143. timeout.tv_usec = 0;
  144. return select(sock + 1, &readfds, NULL, NULL, &timeout);
  145. }
  146. unsigned short CMyPingip::in_cksum(unsigned short* addr, int len)
  147. {
  148. int nleft = len;
  149. unsigned short* w = addr;
  150. unsigned int sum = 0;
  151. unsigned short answer = 0;
  152. while (nleft > 1) {
  153. sum += *w++;
  154. nleft -= 2;
  155. }
  156. if (nleft == 1) {
  157. *(unsigned char*)(&answer) = *(unsigned char*)w;
  158. sum += answer;
  159. }
  160. sum = (sum >> 16) + (sum & 0xffff);
  161. sum += (sum >> 16);
  162. answer = ~sum;
  163. return answer;
  164. }