linux:C语言通过ICMP协议判断局域网内部主机是…
2018-06-17 23:24:19来源:未知 阅读 ()
ICMP协议
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; }
参考:
用C语言实现Ping程序功能:http://www.ibm.com/developerworks/cn/linux/network/ping/index.html
作者: NONO
出处:http://www.cnblogs.com/diligenceday/
QQ:287101329
微信:18101055830
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:算法运行时间复杂度
下一篇:C++ 头文件系列(deque)
- 关于各种不同开发语言之间数据加密方法(DES,RSA等)的互通的 2020-06-07
- C语言程序结构 2020-05-31
- Building & Debugging chromium on CLion for Linu 2020-05-19
- 算法笔记刷题6 ( PAT 1003我要通过 ) 2020-05-08
- 每日干货丨C++语言主流开发工具推荐! 2020-04-28
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash