⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ping.c

📁 此文件为linux环境下的PING程序
💻 C
字号:
#include <stdio.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 <netinet/ip_icmp.h>#include <netdb.h>#include <setjmp.h>#include <errno.h>#define PACKET_SIZE     4096#define MAX_WAIT_TIME   5#define MAX_NO_PACKETS  2		//发包的个数#define ICMP_ECHO 8#define ICMP_ECHOREPLY 0char 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 statistics(int signo){    if (MAX_NO_PACKETS != nreceived)        printf ("not found\n");    else        printf ("found\n");    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;    while(nleft>1)							//把ICMP报头二进制数据以2字节为单位累加起来    {        sum += *w++;        nleft-=2;    }										//若ICMP报头为奇数个字节,会剩下最后一字节。    if( nleft == 1)							//把最后一个字节视为一个2字节数据的高字节,这个2字节数据的低字节为0,继续累加    {        *(unsigned char *)(&answer) = *(unsigned char *)w;        sum += answer;    }    sum = (sum>>16)+(sum&0xffff);    sum += (sum>>16);    answer = ~sum;    return answer;}int pack(int pack_no)						//设置ICMP报头{    int i,packsize;    struct icmp *icmp;    struct timeval *tval;    icmp=(struct icmp*)sendpacket;    icmp->icmp_type = ICMP_ECHO;    icmp->icmp_code = 0;    icmp->icmp_cksum = 0;    icmp->icmp_seq=pack_no;    icmp->icmp_id = pid;    packsize=8+datalen;    tval= (struct timeval *)icmp->icmp_data;    gettimeofday(tval,NULL);				//记录发送时间    icmp->icmp_cksum=cal_chksum( (unsigned short *)icmp,packsize);		//校验算法    return packsize;}void send_packet()							//发送三个ICMP报文{    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报文    }}void recv_packet()							//接收所有ICMP报文{    int n,fromlen;    extern int errno;    signal(SIGALRM,statistics);    fromlen = sizeof(from);    while( nreceived < nsend)    {        alarm(MAX_WAIT_TIME);        if( (n = recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr *)&from,&fromlen)) < 0 ) {            if(errno == EINTR)                continue;        }        gettimeofday(&tvrecv,NULL);			//记录接收时间        if(unpack(recvpacket,n) == -1) {            continue;        }        nreceived++;    }}int unpack(char *buf,int len)				//剥去ICMP报头{    int i,iphdrlen;    struct ip *ip;    struct icmp *icmp;    struct timeval *tvsend;    ip = (struct ip *)buf;    iphdrlen = ip->ip_hl<<2;					//求ip报头长度,即ip报头的长度标志乘4    icmp = (struct icmp *)(buf + iphdrlen);		//越过ip报头,指向ICMP报头    len -= iphdrlen;						    //ICMP报头及ICMP数据报的总长度    if(len < 8)							    	//小于ICMP报头长度则不合理        return -1;								//确保所接收的是我所发的的ICMP的回应    if( (icmp->icmp_type != ICMP_ECHOREPLY) || (icmp->icmp_id != pid) )        return -1;}int main(int argc,char *argv[]){    struct hostent *host;    struct protoent *protocol;    unsigned long inaddr = 0l;    int waittime = MAX_WAIT_TIME;    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");        exit(1);    }    if( (sockfd = socket(AF_INET,SOCK_RAW,protocol->p_proto)) < 0 )	//生成使用ICMP的原始套接字,这种套接字只有root才能生成    {        perror("socket error");        exit(1);    }    setuid(getuid());							//回收root权限,设置当前用户权限    setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size) );    bzero(&dest_addr,sizeof(dest_addr));    dest_addr.sin_family = AF_INET;    if((inaddr = inet_addr(argv[1])) == INADDR_NONE)		//判断是主机名还是ip地址    {        if((host = gethostbyname(argv[1]) ) == NULL)		//是主机名        {            printf("gethostbyname error\n");            exit(1);        }        memcpy( (char *)&dest_addr.sin_addr,host->h_addr,host->h_length);    } else						//是ip地址        dest_addr.sin_addr.s_addr = inaddr;    pid = getpid();				//获取main的进程id,用于设置ICMP的标志符    send_packet();				//发送所有ICMP报文    recv_packet();				//接收所有ICMP报文    statistics(SIGALRM);		//进行统计    return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -