HTML5技术

Linux编程之PING的实现 - 冠军的试炼(2)

字号+ 作者:H5之家 来源:H5之家 2017-01-27 08:06 我要评论( )

int icmp_unpack( char * buf, int len){ int iphdr_len; struct timeval begin_time, recv_time, offset_time; ip* ip_hdr = ( struct ip * )buf;iphdr_len = ip_hdr-ip_hl* 4 ; struct icmp* icmp = ( struct icm

int icmp_unpack(char* buf, int len) { int iphdr_len; struct timeval begin_time, recv_time, offset_time; ip* ip_hdr = (struct ip *)buf; iphdr_len = ip_hdr->ip_hl*4; struct icmp* icmp = (struct icmp*)(buf+iphdr_len); //使指针跳过IP头指向ICMP头 len-=iphdr_len; (len < 8) //判断长度是否为ICMP包长度 { fprintf(stderr, ); return -1; } ((icmp->icmp_type == ICMP_ECHOREPLY) && (icmp->icmp_id == (pid & 0xffff))) { if((icmp->icmp_seq < 0) || (icmp->icmp_seq > PACKET_SEND_MAX_NUM)) { fprintf(stderr, ); return -1; } ping_packet[icmp->icmp_seq].flag = 0; begin_time = ping_packet[icmp->icmp_seq].begin_time; //去除该包的发出时间 gettimeofday(&recv_time, NULL); offset_time = cal_time_offset(begin_time, recv_time); rtt = offset_time.tv_sec*1000 + offset_time.tv_usec/1000; //毫秒为单位 printf(, len, inet_ntoa(ip_hdr->ip_src), icmp->icmp_seq, ip_hdr->ip_ttl, rtt); } else { fprintf(stderr, ); return -1; } return 0; }

 

 

二、发包线程的搭建

根据PING程序的框架,我们需要建立一个线程用于ping包的发送,我的想法是这样的:使用sendto进行发包,发包速率我们维持在1秒1发,我们需要用一个全局变量记录第一个ping包发出的时间,除此之外,我们还需要一个全局变量来记录我们发出的ping包到底有几个,这两个变量用于后来收到ping包回复后的数据计算。

void ping_send() { char send_buf[128]; memset(send_buf, 0, sizeof(send_buf)); gettimeofday(&start_time, NULL); (alive) { int size = 0; gettimeofday(&(ping_packet[send_count].begin_time), NULL); ping_packet[send_count].flag = 1; //将该标记为设置为该包已发送 icmp_pack((struct icmp*)send_buf, send_count, 64); //封装icmp包 size = sendto(rawsock, send_buf, 64, 0, (struct sockaddr*)&dest, sizeof(dest)); send_count++; (size < 0) { fprintf(stderr, ); continue; } sleep(1); } }

 

三、收包线程的搭建
我们同样建立一个接收包的线程,这里我们采用select函数进行收包,并为select函数设置超时时间为200us,若发生超时,则进行下一个循环。同样地,我们也需要一个全局变量来记录成功接收到的ping回复包的数量。

void ping_recv() { struct timeval tv; tv.tv_usec = 200; //设置select函数的超时时间为200us tv.tv_sec = 0; fd_set read_fd; char recv_buf[512]; memset(recv_buf, 0 ,sizeof(recv_buf)); while(alive) { int ret = 0; FD_ZERO(&read_fd); FD_SET(rawsock, &read_fd); ret = select(rawsock+1, &read_fd, NULL, NULL, &tv); switch(ret) { case -1: fprintf(stderr,); break; case 0: break; default: { int size = recv(rawsock, recv_buf, sizeof(recv_buf), 0); if(size < 0) { fprintf(stderr,); continue; } ret = icmp_unpack(recv_buf, size); (ret == -1) //不是属于自己的icmp包,丢弃不处理 { continue; } recv_count++; //接收包计数 } break; } } }

 

 

四、中断处理

我们规定了一次ping发送的包的最大值为64个,若超出该数值就停止发送。作为PING的使用者,我们一般只会发送若干个包,若有这几个包顺利返回,我们就crtl+c中断ping。这里的代码主要是为中断信号写一个中断处理函数,将alive这个全局变量设置为0,进而使发送ping包的循环停止而结束程序。

void icmp_sigint(int signo) { alive = 0; gettimeofday(&end_time, NULL); time_interval = cal_time_offset(start_time, end_time); } signal(SIGINT, icmp_sigint);

 

 

五、总体实现

各模块介绍完了,现在贴出完整代码。

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • Linux编程之给你的程序开后门 - 冠军的试炼

    Linux编程之给你的程序开后门 - 冠军的试炼

    2017-01-16 15:00

  • Web Worker javascript多线程编程(一) - PeakLeo

    Web Worker javascript多线程编程(一) - PeakLeo

    2016-12-27 10:00

  • 怎样实现前端裁剪上传图片功能 - 会编程的银猪

    怎样实现前端裁剪上传图片功能 - 会编程的银猪

    2016-10-19 13:00

  • 【菜鸟玩Linux开发】通过MySQL自动同步刷新Redis - zhxilin

    【菜鸟玩Linux开发】通过MySQL自动同步刷新Redis - zhxilin

    2016-10-03 16:00

网友点评
s