700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > linux c icmp协议 判断主机存活

linux c icmp协议 判断主机存活

时间:2022-02-11 05:36:01

相关推荐

linux c icmp协议 判断主机存活

详细参考

《linux c ping 分析实现》

/whatday/article/details/104192608

ICMP(Internet Control Message,网际控制报文协议)是为网关和目标主机而提供的一种差错控制机制,使它们在遇到差错时能把错误报告给报文源发方。

ICMP协议是IP层的一个协议,但是由于差错报告在发送给报文源发方时可能也要经过若干子网,因此牵涉到路由选择等问题,所以ICMP报文需通过IP协议来发送。

ICMP数据报的数据发送前需要两级封装:首先添加ICMP报头形成ICMP报文,再添加IP报头形成IP数据报。

main.cpp:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <strings.h>#include <signal.h>#include <sys/time.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>#include <sys/select.h>#include <fcntl.h>#define PACKET_SIZE 4096/* 计算校验和的算法 */unsigned short cal_chksum(unsigned short *addr,int len){int sum=0;int nleft = len;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; /* 这里将 answer 转换成 int 整数 */}sum = (sum >> 16) + (sum & 0xffff); /* 高位低位相加 */sum += (sum >> 16); /* 上一步溢出时,将溢出位也加到sum中 */answer = ~sum; /* 注意类型转换,现在的校验和为16位 */return answer;}int livetest(char* ip) {char sendpacket[PACKET_SIZE]; /* 发送的数据包 */char recvpacket[PACKET_SIZE]; /* 接收的数据包 */pid_t pid;int datalen = 56; /* icmp数据包中数据的长度 */struct protoent *protocol;protocol = getprotobyname("icmp");int sockfd;int size = 50*1024;if((sockfd = socket(AF_INET, SOCK_RAW, protocol->p_proto)) < 0) {perror("socket error");}setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size) );struct sockaddr_in dest_addr;bzero(&dest_addr, sizeof(dest_addr));dest_addr.sin_family = AF_INET;dest_addr.sin_addr.s_addr = inet_addr(ip);//send packet;int packsize;struct icmp *icmp;struct timeval *tval;icmp = (struct icmp*)sendpacket;icmp->icmp_type = ICMP_ECHO; /* icmp的类型 */icmp->icmp_code = 0; /* icmp的编码 */icmp->icmp_cksum = 0; /* icmp的校验和 */icmp->icmp_seq = 1; /* icmp的顺序号 */icmp->icmp_id = pid; /* icmp的标志符 */packsize = 8 + datalen; /* icmp8字节的头 加上数据的长度(datalen=56), packsize = 64 */tval = (struct timeval *)icmp->icmp_data; /* 获得icmp结构中最后的数据部分的指针 */gettimeofday(tval, NULL); /* 将发送的时间填入icmp结构中最后的数据部分 */icmp->icmp_cksum = cal_chksum((unsigned short *)icmp, packsize);/*填充发送方的校验和*/if(sendto(sockfd, sendpacket, packsize, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) < 0){perror("sendto error");}printf("send %d, send done\n",1 );int n;struct sockaddr_in from;int fromlen = sizeof(from);fcntl(sockfd, F_SETFL, O_NONBLOCK);struct timeval timeo = {1,0};fd_set set;FD_ZERO(&set);FD_SET(sockfd, &set);//read , write;int retval = select(sockfd+1, &set, NULL, NULL, &timeo);if(retval == -1) {printf("select error\n");return 0;}else if(retval == 0 ) {printf("timeout\n");return 0;}else{if( FD_ISSET(sockfd, &set) ){printf("host is live\n");return 1;}}// n = recvfrom(sockfd, recvpacket,sizeof(recvpacket), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen);// if(n<0) {//perror("recvfrom error");// }else{//printf("%d\n",n);// }//return 0;}int main(int argc, char* argv[]) {printf("%d\n" , livetest(argv[1]));return 0;}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。