#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; /*