自己写的一个ping程序

 /*

* 编写于2010-9-22晚,姓名:ringk

* ping程序:用于测试网络连接状况

* 参考书籍《Linux网络编程》

* 如有问题,邮箱:gisyhy@163.com, QQ:986418764

*/

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

#include <netinet/ip.h>

#include <netinet/ip_icmp.h>

#include <netinet/in.h> //sockaddr_in

#include <sys/socket.h>

#include <sys/ioctl.h>

 

#include <sys/time.h>

#include <netdb.h>

#include <signal.h>

#include <pthread.h>

 

//#include "fun.h"

 

#define SENDBUF              256  //发送时间缓存

#define RECVBUFSIZE      1024         //接受缓存

#define SENDBUFSIZE      72     //发送缓存

 

typedef struct icmpsend

{

         struct timeval          sendtime;

         int            seq;

}icmpsend;

 

static struct icmpsend              psd[SENDBUF];

static struct sockaddr_in        dest_addr;

static struct timeval                  t_sat,t_end;    //ping到总时间

static char                           dest_str[60];   //地址别名

static int                             alive;                  //线程保时

static int                             pid;            //本进程id

static int                             sock;                 

static int                             seq_send,seq_recv;//发送和接受到ICMP包个数

static pthread_t               psendid,precvid;//发送和接受线程

 

short icmp_cksum(char *sendbuf,int len)//检验和

{

         int sum=0;

         int odd= len & 0x1;

        

         char *value =sendbuf;

         while(len & 0xfffe){

                   sum += *((short *)value);

                   value += 2;

                   len -=2;

         }

        

         if(odd)sum += (short)(((*value)<<8) & 0xff00);//奇偶判断

        

         sum = (sum>>16) + (sum & 0xffff);//注意求和

         sum += (sum>>16);

        

         return (~sum) & 0xffff;//注意取反

}

void icmp_pack(struct icmp *picmp,int len)//打包

{

         picmp->icmp_type =ICMP_ECHO;//回显请求

         picmp->icmp_code=0;

         picmp->icmp_cksum=0;

         picmp->icmp_id=pid;

         picmp->icmp_seq = seq_send & 0xffff;

         int i=0;

         for(;i<len;i++)

                   picmp->icmp_data[i]=i;

         picmp->icmp_cksum = icmp_cksum((char *)picmp,len);

}

double icmp_sub(struct timeval begin,struct timeval end)//时间计算

{

         double sec = end.tv_sec-begin.tv_sec;

         double usec = end.tv_usec-begin.tv_usec;

         //printf("%.1lf/n",usec);

         if(usec <0){

                   sec -=1.0;

                   usec += 1000000.0;

         }

         return sec*1000+usec/1000;

}

icmpsend * findsend(int seq)//在发送时间缓存里找到序列号匹配

{

         int i;

         if(seq ==-1){

                   for(i=0;i<SENDBUF;i++)

                            if(psd[i].seq==0)

                                     return (psd+i);

         }

         else if(seq >0){

                   for(i=0;i<SENDBUF;i++)

                            if(psd[i].seq ==seq)

                                     return (psd+i);

         }

         return 0;

}

 

void icmp_unpack(char *rbuf,int len,struct timeval tr)//解包,注意接受到的为IP

{

         struct ip *pip=(struct ip *)rbuf;

         struct icmp *picmp= (struct icmp *)(rbuf +pip->ip_hl*4);

 

         if(len-pip->ip_hl*4 <8){

                   printf("recv data less than 8/n");

                   return ;

         }

 

         if(picmp->icmp_type == ICMP_ECHOREPLY && picmp->icmp_id==pid){

                   //printf("test goto icmp/n");

                   seq_recv ++;

                   struct icmpsend *pcur = findsend(picmp->icmp_seq);

                   if(pcur==0)return ;

                  

                   struct timeval ts = pcur->sendtime;

                   double rtt = icmp_sub(ts,tr);

                   printf("%d bytes from %s: icmp_seq=%d ttl=%d rtt=%.1lf ms/n",

                            len-pip->ip_hl*4,

                            inet_ntoa(pip->ip_src),

                            pcur->seq,

                            pip->ip_ttl,

                            rtt);

                   pcur->seq =0;

         }

                  

}

void icmp_send(void *argv)//发送线程

{

         printf("PING %s(%s) 64 bytes of data./n",

                   inet_ntoa(dest_addr.sin_addr.s_addr),

                   dest_str);

                  

         gettimeofday(&t_sat,0);

         struct timeval ts;

         char send_buf[SENDBUFSIZE];

         int addr_len= sizeof(struct sockaddr_in);

         while(alive){

                  memset(send_buf,0,SENDBUFSIZE);

                   icmp_pack((struct icmp *)send_buf,64);

                   gettimeofday(&ts,0);

                   //printf("test send data/n");

                   //注意发送的包为ICMP

                   if(sendto(sock,send_buf,64,0,(struct sockaddr *)&dest_addr,addr_len)==-1){

                            printf("send failed/n");

                            alive=0;

                            break;

                   }

                   icmpsend * psend= findsend(-1);//找到一个空余位置,存放发送到时间

                   if(psend ==0){

                            printf("size to max/n");

                            alive=0;

                            break;

                   }

                   else {

                            psend->sendtime = ts;

                            psend->seq = seq_send++;

                   }

                   sleep(5);

         }

}

void icmp_recv(void *argv)//接受线程

{

         char recv_buf[RECVBUFSIZE];

         struct timeval tr;

         struct timeval timeout;

         fd_set readfd;

         int sel;

         while(alive){

                   FD_ZERO(&readfd);

                   FD_SET(sock,&readfd);

                   timeout.tv_sec=5;

                   timeout.tv_usec =0;

                   if((sel=select(sock+1,&readfd,0,0,&timeout)) >0){

                            //printf("test recv data/n");

                            //注意接受的包为IP

                            int cb =recv(sock,recv_buf,RECVBUFSIZE,0);

                            //printf("test recv size:%d/n",cb);

                            gettimeofday(&tr,0);

                            if(cb <0){

                                     printf("recv error/n");

                                     alive=0;

                                     break;

                            }

                            icmp_unpack(recv_buf,cb,tr);

                            //showpacket(recv_buf,cb);

                   }

                   //else if(sel==0)printf("timeout/n");

         }

                  

}

void signo(int sig)//SIGINT信号

{

         alive =0;

         pthread_cancel(psendid);

         pthread_cancel(precvid);

}

int main(int argc,char *argv[])

{

         char dest[30];

         if(argc <2)strcpy(dest,"127.0.0.1");

         else strcpy(dest,argv[1]);

        

         memset(psd,0,sizeof(psd));

         memset(&dest_addr,0,sizeof(dest_addr));

         alive=1;

         sock=-1;

         seq_send=1;

         seq_send =0;

         psendid=0;

         precvid =0;

         pid =getpid();

         signal(SIGINT,signo);

        

         struct hostent *hst=0;

         int inaddr=inet_addr(dest);

         if(inaddr ==INADDR_NONE){

                   strcpy(dest_str,dest);

                   hst=gethostbyname(dest);

                   if(hst ==0){

                            printf("gethostbyname error/n");

                            return 0;

                   }

                   dest_addr.sin_addr.s_addr= *((int*)*(hst->h_addr_list));

         }

         else {

                   //hst=gethostbyaddr((void*)&inaddr,sizeof(inaddr),AF_INET);

                   //if(hst)strcpy(dest_str,*(hst->h_aliases));

                   strcpy(dest_str,dest);

                   dest_addr.sin_addr.s_addr= inaddr;

         }

         dest_addr.sin_family = AF_INET;

        

         sock=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);//注意协议类型

         if(sock <0){

                   printf("socket error/n");

                   return 0;

         }

        

         if(pthread_create(&psendid,0,&icmp_send,0) <0){

                   printf("create send thread error/n");

                   return 0;

         }

        

         if(pthread_create(&precvid,0,&icmp_recv,0)<0){

                   printf("create recv thread error/n");

                   return 0;

         }

        

         pthread_join(psendid,0);

         pthread_join(precvid,0);

        

         gettimeofday(&t_end,0);

         printf("/n--- %s ping statistics ---/n",inet_ntoa(dest_addr.sin_addr.s_addr));

         printf("%d packets transmitted,%d received,%.2lf%c packets loss,time %.0lf ms./n",

                   seq_send--,

                   seq_recv,

                   1.0*(seq_send-seq_recv)/seq_send,

                   '%',

                   icmp_sub(t_sat,t_end));

         close(sock);

         return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值