LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 443|回复: 1

写了一个ping程序,但是只能收到一个reply然后就阻塞了,谁能帮我看看?

[复制链接]
发表于 2005-1-13 03:16:30 | 显示全部楼层 |阅读模式

  1. // file: ping.cpp
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include <unistd.h>
  5. #include <arpa/inet.h>
  6. #include <netinet/in.h>
  7. #include <stdio.h>
  8. #include <time.h>
  9. #include <netinet/in_systm.h>
  10. #include <netinet/ip.h>
  11. #include <netinet/ip_icmp.h>
  12. #include <sys/time.h>
  13. #include <string.h>
  14. #include <signal.h>
  15. #include <netdb.h>

  16. int fd = 0;
  17. struct addrinfo *ai = NULL;
  18. int pid = 0;

  19. struct addrinfo *host_serv(const char *host, const char *serv, int family, int socktype)
  20. {
  21.         struct addrinfo hints, *res = NULL;
  22.         memset(&hints, 0, sizeof(hints));
  23.         hints.ai_flags = AI_CANONNAME;
  24.         hints.ai_family = family;
  25.         hints.ai_socktype = socktype;
  26.         int n = getaddrinfo(host, serv, &hints, &res);
  27.         if (n != 0)
  28.                 return NULL;
  29.         return res;
  30. }

  31. void tv_sub(struct timeval *out, struct timeval *in)
  32. {
  33.         out->tv_usec -= in->tv_usec;
  34.         if (out->tv_usec < 0) {
  35.                 --out->tv_sec;
  36.                 out->tv_usec += 1000000;
  37.         }
  38.         out->tv_sec -= in->tv_sec;
  39. }

  40. unsigned short in_cksum(unsigned short *addr, int len)
  41. {
  42.         int left = len;
  43.         int sum = 0;
  44.         unsigned short *ptr = addr;
  45.         while (left > 1) {
  46.                 sum += *ptr++;
  47.                 left -= 2;
  48.         }
  49.        
  50.         unsigned short answer = 0;
  51.         if (left == 1) {
  52.                 *(unsigned char *)(&answer) = *(unsigned char *)ptr;
  53.                 sum += answer;
  54.         }
  55.        
  56.         sum = (sum >> 16) + (sum & 0xffff);
  57.         sum += (sum >> 16);
  58.         answer = ~sum;
  59.         return answer;
  60. }

  61. void recv_ping(char *ptr, ssize_t len, struct timeval *tvrecv)
  62. {
  63.         if (len < sizeof(struct ip))
  64.                 return;
  65.         struct ip *ip_ptr = (struct ip *)ptr;
  66.         int ip_hlen = (ip_ptr->ip_hl << 2);
  67.         struct icmp *icmp_ptr = (struct icmp *)(ptr + ip_hlen);
  68.         int icmp_len = len - ip_hlen;
  69.         if (icmp_len < 8)
  70.                 return;
  71.         if (icmp_ptr->icmp_type == ICMP_ECHOREPLY) {
  72.                 if (icmp_ptr->icmp_id != pid)
  73.                         return;
  74.                 if (icmp_len < 16)
  75.                         return;
  76.                 struct timeval *tvsend = (struct timeval *)icmp_ptr->icmp_data;
  77.                 tv_sub(tvrecv, tvsend);
  78.                 double rtt = tvrecv->tv_sec * 1000.0 + tvrecv->tv_usec / 1000.0;
  79.                
  80.                 printf("%d bytes: seq=%u, ttl=%d, rtt=%.3fms\n",
  81.                         icmp_len,
  82.                         icmp_ptr->icmp_seq,
  83.                         ip_ptr->ip_ttl,
  84.                         rtt);
  85.         }
  86. }

  87. void send_ping(int fd, struct addrinfo *addr, int pid)
  88. {
  89.         static int seq = 0;
  90.         char buff[1024];
  91.         struct icmp *icmp_ptr = (struct icmp *)buff;
  92.         icmp_ptr->icmp_type = ICMP_ECHO;
  93.         icmp_ptr->icmp_code = 0;
  94.         icmp_ptr->icmp_id = pid;
  95.         icmp_ptr->icmp_seq = ++seq;
  96.         memset(icmp_ptr->icmp_data, 0xa5, 56);
  97.        
  98.         gettimeofday((struct timeval *)icmp_ptr->icmp_data, NULL);
  99.         int len = sizeof(timeval) + 56;
  100.         icmp_ptr->icmp_cksum = in_cksum((u_short*)icmp_ptr, len);

  101.         sendto(fd, buff, len, 0, addr->ai_addr, addr->ai_addrlen);
  102. }

  103. void sig_alarm(int signo)
  104. {
  105.         send_ping(fd, ai, pid);
  106.         alarm(1);
  107. }

  108. int main(int argc, char *argv[])
  109. {
  110.         if (argc != 2)
  111.         {
  112.                 printf("Usage: %s <ip>\n", argv[0]);
  113.                 return -1;
  114.         }

  115.         fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
  116.         if (fd < 0)
  117.         {
  118.                 printf("Failed to create socket!\n");
  119.                 return -1;
  120.         }
  121.         ai = host_serv(argv[1], NULL, 0, 0);
  122.         if (!ai)
  123.         {
  124.                 printf("Failed to get address of %s\n", argv[1]);
  125.                 return -1;
  126.         }
  127.        
  128.         pid = getpid();
  129.         signal(SIGALRM, sig_alarm);
  130.         sig_alarm(SIGALRM);
  131.        
  132.         char buff[1024];
  133.         char addr[1024];
  134.         for (;;)
  135.         {
  136.                 socklen_t len = sizeof(ai->ai_addrlen);
  137.                 ssize_t n = recvfrom(fd, buff, sizeof(buff), 0, (sockaddr*)addr, &len);
  138.                 if (n > 0)
  139.                 {
  140.                         struct timeval tv;
  141.                         gettimeofday(&tv, NULL);
  142.                         recv_ping(buff, n, &tv);
  143.                 }
  144.         }
  145.         return 0;
  146. }
复制代码

编译:#g++ -g -o ping ping.cpp
 楼主| 发表于 2005-1-13 04:37:09 | 显示全部楼层
明白了,是校验和的问题。
icmp_ptr->icmp_cksum = 0; // <== 加上这一句
icmp_ptr->icmp_cksum = in_cksum((u_short*)icmp_ptr, len);
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表