Linux用ICMP协议实现简单Ping网络监测功能
- #include <stdio.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/ip.h>
- #include <netinet/ip_icmp.h>
- #include <netdb.h>
- #define PACKET_SIZE 4096
- #define ERROR 0
- #define SUCCESS 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)
- {
- sum += *w++;
- nleft -= 2;
- }
- if( nleft == 1)
- {
- *(unsigned char *)(&answer) = *(unsigned char *)w;
- sum += answer;
- }
- sum = (sum >> 16) + (sum & 0xffff);
- sum += (sum >> 16);
- answer = ~sum;
- return answer;
- }
- // Ping函数
- int ping( char *ips, int timeout)
- {
- struct timeval *tval;
- int maxfds = 0;
- fd_set readfds;
- struct sockaddr_in addr;
- struct sockaddr_in from;
- // 设定Ip信息
- bzero(&addr,sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = inet_addr(ips);
- int sockfd;
- // 取得socket
- sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
- if (sockfd < 0)
- {
- printf("ip:%s,socket error\n",ips);
- return ERROR;
- }
- struct timeval timeo;
- // 设定TimeOut时间
- timeo.tv_sec = timeout / 1000;
- timeo.tv_usec = timeout % 1000;
- if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)) == -1)
- {
- printf("ip:%s,setsockopt error\n",ips);
- return ERROR;
- }
- char sendpacket[PACKET_SIZE];
- char recvpacket[PACKET_SIZE];
- // 设定Ping包
- memset(sendpacket, 0, sizeof(sendpacket));
- pid_t pid;
- // 取得PID,作为Ping的Sequence ID
- pid=getpid();
- struct ip *iph;
- struct icmp *icmp;
- icmp=(struct icmp*)sendpacket;
- icmp->icmp_type=ICMP_ECHO; //回显请求
- icmp->icmp_code=0;
- icmp->icmp_cksum=0;
- icmp->icmp_seq=0;
- icmp->icmp_id=pid;
- tval= (struct timeval *)icmp->icmp_data;
- gettimeofday(tval,NULL);
- icmp->icmp_cksum=cal_chksum((unsigned short *)icmp,sizeof(struct icmp)); //校验
- int n;
- // 发包
- n = sendto(sockfd, (char *)&sendpacket, sizeof(struct icmp), 0, (struct sockaddr *)&addr, sizeof(addr));
- if (n < 1)
- {
- printf("ip:%s,sendto error\n",ips);
- return ERROR;
- }
- // 接受
- // 由于可能接受到其他Ping的应答消息,所以这里要用循环
- while(1)
- {
- // 设定TimeOut时间,这次才是真正起作用的
- FD_ZERO(&readfds);
- FD_SET(sockfd, &readfds);
- maxfds = sockfd + 1;
- n = select(maxfds, &readfds, NULL, NULL, &timeo);
- if (n <= 0)
- {
- printf("ip:%s,Time out error\n",ips);
- close(sockfd);
- return ERROR;
- }
- // 接受
- memset(recvpacket, 0, sizeof(recvpacket));
- int fromlen = sizeof(from);
- n = recvfrom(sockfd, recvpacket, sizeof(recvpacket), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen);
- if (n < 1) {
- break;
- }
- char *from_ip = (char *)inet_ntoa(from.sin_addr);
- // 判断是否是自己Ping的回复
- if (strcmp(from_ip,ips) != 0)
- {
- printf("NowPingip:%s Fromip:%s\nNowPingip is not same to Fromip,so ping wrong!\n",ips,from_ip);
- return ERROR;
- }
- iph = (struct ip *)recvpacket;
- icmp=(struct icmp *)(recvpacket + (iph->ip_hl<<2));
- printf("ip:%s\n,icmp->icmp_type:%d\n,icmp->icmp_id:%d\n",ips,icmp->icmp_type,icmp->icmp_id);
- // 判断Ping回复包的状态
- if (icmp->icmp_type == ICMP_ECHOREPLY && icmp->icmp_id == pid) //ICMP_ECHOREPLY回显应答
- {
- // 正常就退出循环
- break;
- }
- else
- {
- // 否则继续等
- continue;
- }
- }
- int main()
- {
- char cPing[16];
- printf("Please input ping IP:");
- scanf("%s",cPing);
- if(ping(cPing,10000))
- {
- printf("Ping succeed!\n");
- }
- else
- {
- printf("Ping wrong!\n");
- }
- }
测试结果:
Please input ping IP:192.168.1.155
Nowip:192.168.1.155 Fromip:192.168.1.133
Nowip is not same to Fromip,so ping wrong!
Ping wrong!
root@an-virtual-machine:~/wyz/test# ./testping
Please input ping IP:192.168.1.188
ip:192.168.1.188
,icmp->icmp_type:0
,icmp->icmp_id:27865
Ping succeed!
Linux用ICMP协议实现简单Ping网络监测功能的更多相关文章
- ICMP 协议仿真及ping命令用途
1.实验目的 加深对 IPv4 协议首部各定义域的理解,掌握路由表的结构和基本配置命令,熟悉 ICMP 的调试操作. 2.实验原理 IPv4 协议定义,网络层协议的相关 RFC 定义和描述. 3.实验 ...
- 002.ICMP--拼接ICMP包,实现简单Ping程序(原始套接字)
一.大致流程: 将ICMP头和时间数据设置好后,通过创建好的原始套接字socket发出去.目的主机计算效验和后会将数据原样返回,用当前时间和返回的数据结算时间差,计算出rtt. 二.数据结构: ICM ...
- ICMP协议、DNS、ARP协议、ping、DHCP协议
1.ICMP协议 1)ICMP协议,即:网络控制消息协议(Internet Control Message Protocol) 2)ICMP是网络层协议,因为ICMP报文是装在IP数据报中,作为它的数 ...
- 三、ARP协议和ICMP协议
一.ARP协议 网络设备有数据要发送到另一台网络设备时,必须要知道对方的网络层地址(IP).IP地址由网络层来提供,但是仅有IP地址是不够的,IP数据报文必须封装成帧才能通过数据链路进行发送.数据帧必 ...
- (转)协议森林06 瑞士军刀 (ICMP协议)
协议森林06 瑞士军刀 (ICMP协议) 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 到现在为止,我们讲解了网络层中最重要的I ...
- UNIX网络编程——利用ARP和ICMP协议解释ping命令
一.MTU 以太网和IEEE 802.3对数据帧的长度都有限制,其最大值分别是1500和1492字节,将这个限制称作最大传输单元(MTU,Maximum Transmission Unit) ...
- 【网络协议】ICMP协议、Ping、Traceroute
ICMP协议 ICMP常常被觉得是IP层的一个组成部分,它是网络层的一个协议.它传递差错报文以及其它须要注意的信息.ICMP报文通常被IP层或更高层(TCP.UDP等)使用,它是在IP数据报内 ...
- PING的原理以及ICMP协议
主要内容: 1.ping的原理以及工作过程 2.ICMP协议 3.ICMP的应用:ping,traceroute 1.ping的原理以及工作过程 ping的原理 ping 程序是用来探测主机到主机 ...
- 4.ICMP协议,ping和Traceroute
1.IMCP协议介绍 前面讲到了,IP协议并不是一个可靠的协议,它不保证数据被送达,那么,自然的,保证数据送达的工作应该由其他的模块来完成.其中一个重要的模块就是ICMP(网络控制报文)协议. 当传送 ...
随机推荐
- pymysql操作数据库、索引、慢日志管理
目录 pymysql操作数据库 简单操作 sql的注入问题 sql注入问题解决办法 sql注入问题模板总结 利用pymysql操作数据库 (增删改),conn.commit() 索引 1.为何要有索引 ...
- C# 跨窗体事件
跨窗体事件:例如从一个窗体改变另一个窗体button的颜色,首先需要将需要改变button的属性改为public using System; using System.Drawing; using S ...
- JS 全局作用域和局部作用域
一.作用域 1.什么是作用域(Scope) 通常来说,一段程序代码中所用到的名字不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域. JS作用域:就是代码名字(变量)作用的范围 ...
- vs 2019 调试web项目 浏览器
- UOJ #460. 新年的拯救计划 神仙题+构造
对于这个神仙题,我还能说什么~ 第一个答案=$n/2$ 还是比较好猜的. 对于构造这个树,大概就是先从 $1$ 号节点向 $n/2$ 距离以内都连一条边,再在第 $n/2$ 个节点进行这个操作,然后从 ...
- 【PKUSC2019】线弦图【计数】【树形DP】【分治FFT】
Description 定义线图为把无向图的边变成点,新图中点与点之间右边当且仅当它们对应的边在原图中有公共点,这样得到的图. 定义弦图为不存在一个长度大于3的纯环,纯环的定义是在环上任取两个不相邻的 ...
- PyCharm中Qt Designer+PyUIC配置
本文环境配置: 系统=>windows10:64位 语言=>Python:3.7.1 第三方库PyQT5:5.11.3pyqt5-tools:5.11.3.1.4 工具=>PyCha ...
- ...扩展运算符+rest参数+call/apply/bind
之前在set,map里面有提过扩展运算符的概念,但是今天偶然遇到一个问题,类似于扩展运算符的经典用法,突然发现对其了解不是很深,所以再来整理一下扩展运算符的相关知识. 重点:扩展运算符内部调用的是数据 ...
- grep家族、sed、awk
一.grep家族 grep是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来. 在上一次的博客中已经使用过egrep通过正则表达式来匹配正确IP地址,这里的用法就不多说了. f ...
- JavaScript 普通声明式函数
1.为什么需要函数 实现代码的复用.存在函数提升,且会在变量提升的上面; 2.函数的创建 js中函数语法: function 函数名(形参){ //函数体 } 调用时:函数名(形参) 注: (1) 形 ...