實現ping命令的代碼

來源:互聯網
上載者:User
#include    <stdio.h>#include    <sys/time.h>#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    <netdb.h>#include    <setjmp.h>#include    <errno.h>#include    <netinet/ip_icmp.h>#include    <string.h>#include    <stdlib.h>#define    PACKET_SIZE 4096            /*  */#define MAX_WAIT_TIME 5#define MAX_NO_PACKETS 3    char sendpacket[PACKET_SIZE];char recvpacket[PACKET_SIZE];int sockfd,datalen=56;int nsend=0,nreceived=0;struct sockaddr_in dest_addr;pid_t pid;struct sockaddr_in from;struct timeval tvrecv;void statistics(int signo);unsigned short cal_chksum(unsigned short *addr,int len);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);    void statistics(int signo){   printf("\n-----------------PING statistics----------------\n");   printf("%d packet transmitted,%d received,%%%d lost \n",nsend,nreceived,(nsend-nreceived)/nsend*100);   close(sockfd);   exit(1);}/*校正和演算法*/unsigned short cal_chksum(unsigned short *addr,int len){   int nleft=len;   int sum=0;   unsigned short *w=addr;   unsigned short answer=0;   /*把ICMP前序位元據以2位元組為單位累加起來*/   while(nleft>1)   {       sum+=*w++;       nleft-=2;   }   /*若ICMP前序為奇數個位元組,會剩下最後一個位元組。把最後一個位元組視為2位元組資料的高位元組,這個2位元組資料的低位元組為0,繼續累加*/   if(nleft==1)   {       *(unsigned char *)(&answer)=*(unsigned char *)w;       sum+=answer;   }   sum=(sum>>16)+(sum&0xffff);   sum+=(sum>>16);   answer=~sum;   return answer;}/*設定ICMP前序*/int pack(int pack_no){   int packsize;   struct icmp *icmpp;   struct timeval *tval;   icmpp=(struct icmp *)sendpacket;   icmpp->icmp_type=ICMP_ECHO;   icmpp->icmp_code=0;   icmpp->icmp_cksum=0;   icmpp->icmp_seq=pack_no;   icmpp->icmp_id=pid;   packsize=8+datalen;   tval=(struct timeval *)icmpp->icmp_data;   gettimeofday(tval,NULL);/*記錄發送時間*/   icmpp->icmp_cksum=cal_chksum((unsigned short*)icmpp,packsize);/*校正演算法*/   return packsize;}/*發送3個ICMP報文*/void send_packet(){   int packetsize;   while(nsend<MAX_NO_PACKETS)   {       nsend++;       packetsize=pack(nsend);/*設定ICMP報文*/       if(sendto(sockfd,sendpacket,packetsize,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr))<0)       {           perror("sendto error");           continue;       }       sleep(1);/*每隔一秒發送一個ICMP報文*/   }}/*接收所有ICMP報文*/void recv_packet(){   int n,fromlen;   extern int errno;  /*更多精彩內容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/cplus/*/   signal(SIGALRM,statistics);   fromlen=sizeof(from);   while(nreceived<10)   {       alarm(MAX_WAIT_TIME);       if((n=recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr *)&from,&fromlen))<0)       {           if(errno==EINTR)           {               continue;           }           perror("recvfrom error\n");           continue;       }       gettimeofday(&tvrecv,NULL); /*記錄接收時間*/       if(unpack(recvpacket,n)==-1)           continue;       nreceived++;   }}/*剝去ICMP前序*/int unpack(char *buf,int len){   int iphdrlen;   struct ip *ipp;   struct icmp *icmpp;   struct timeval *tvsend;   int rtt;   ipp=(struct ip *)buf;   iphdrlen=(ipp->ip_hl)*4;/*求IP前序長度,即IP前序的長度標誌乘4*/   icmpp=(struct icmp*)(buf+iphdrlen);/*超過IP前序,指向ICMP前序*/   len-=iphdrlen;/*ICMP前序及ICMP資料報的總長度*/   if(len<8)/*小於ICMP前序長度則不合理*/   {       printf("ICMP packets\'s length is less than 8\n");       return -1;   }   /*確保所接收的是使用者所發的ICMP的回應*/   if((icmpp->icmp_type==ICMP_ECHOREPLY)&&(icmpp->icmp_id==pid))   {       tvsend=(struct timeval *)icmpp->icmp_data;       tv_sub(&tvrecv,tvsend); /*接收和發送的時間差*/       rtt=tvrecv.tv_sec*1000+tvrecv.tv_usec/1000;/*以毫秒為單位計算rtt*/       /*顯示相關資訊*/       printf("%d byte from %s:icmp_seq=%u ttl=%d rtt=%d  ms\n",               len,inet_ntoa(from.sin_addr),icmpp->icmp_seq,ipp->ip_ttl,rtt);   }   else       return -1;}void tv_sub(struct timeval *out,struct timeval *in){   if((out->tv_usec-=in->tv_usec)<0)   {       out->tv_sec-=1;       out->tv_usec+=1000000;   }   out->tv_sec-=in->tv_sec;}int main(int argc,char **argv){   struct hostent *host;   struct protoent *protocol;   int size=50*1024;   if(argc<2)   {       printf("usage : %s hostname/IP address \n",argv[0]);       exit(1);   }   if((protocol=getprotobyname("icmp"))==NULL)   {       perror("getprotobyname\n");       exit(1);   }   /*產生使用ICMP的原始通訊端,這種通訊端只是root才能產生*/   if((sockfd=socket(AF_INET,SOCK_RAW,protocol->p_proto))<0)   {       perror("socket error\n");       exit(1);   }   /*回收root許可權,設定目前使用者許可權*/   setuid(getuid());   /*擴大通訊端接收緩衝區到50K,這樣做主要為了減少接收緩衝區溢位的可能性,若無意中ping一個廣播位址或多播地址,將會引來大量應答*/   setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size));   bzero(&dest_addr,sizeof(dest_addr));   dest_addr.sin_family=AF_INET;   if((host=gethostbyname(argv[1]))==NULL)   {       perror("gethostbyname error\n");       exit(1);   }   dest_addr.sin_addr=*((struct in_addr *)host->h_addr);   pid=getpid();   printf("PING %s(%s): %d bytes data in ICMP packets.\n",argv[1],inet_ntoa(dest_addr.sin_addr),datalen);   send_packet();/*發送所有ICMP報文*/   recv_packet();/*接收所有ICMP報文*/   statistics(SIGALRM);/*進行統計*/       return 0;}

本文出自 “好好活著” 部落格,請務必保留此出處http://wolfword.blog.51cto.com/4892126/1225685

相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。