ICMP是(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。
ICMP协议是一种面向无连接的协议,用于传输出错报告控制信息。它是一个非常重要的协议,它对于网络安全具有极其重要的意义。
 
折腾半天,原来ICMP也是TCP/IP其中一种协议.那么监测网络是否ping的通,就跟TCP协议差不多了。
步骤简单归纳为:1.绑定套接字,2.发送数据包 3.接收数据包 4.解析数据包
  1. #include <stdio.h>
  2. #include <sys/socket.h>
  3. #include <netinet/in.h>
  4. #include <netinet/ip.h>
  5. #include <netinet/ip_icmp.h>
  6. #include <netdb.h>
  1. #define PACKET_SIZE     4096
  2. #define ERROR           0
  3. #define SUCCESS         1
  4. //效验算法(百度下有注释,但是还是看不太明白)
  5. unsigned short cal_chksum(unsigned short *addr, int len)
  6. {
  7. int nleft=len;
  8. int sum=0;
  9. unsigned short *w=addr;
  10. unsigned short answer=0;
  11. while(nleft > 1)
  12. {
  13. sum += *w++;
  14. nleft -= 2;
  15. }
  16. if( nleft == 1)
  17. {
  18. *(unsigned char *)(&answer) = *(unsigned char *)w;
  19. sum += answer;
  20. }
  21. sum = (sum >> 16) + (sum & 0xffff);
  22. sum += (sum >> 16);
  23. answer = ~sum;
  24. return answer;
  25. }
  26. // Ping函数
  27. int ping( char *ips, int timeout)
  28. {
  29. struct timeval *tval;
  30. int maxfds = 0;
  31. fd_set readfds;
  32. struct sockaddr_in addr;
  33. struct sockaddr_in from;
  34. // 设定Ip信息
  35. bzero(&addr,sizeof(addr));
  36. addr.sin_family = AF_INET;
  37. addr.sin_addr.s_addr = inet_addr(ips);
  38. int sockfd;
  39. // 取得socket
  40. sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
  41. if (sockfd < 0)
  42. {
  43. printf("ip:%s,socket error\n",ips);
  44. return ERROR;
  45. }
  46. struct timeval timeo;
  47. // 设定TimeOut时间
  48. timeo.tv_sec = timeout / 1000;
  49. timeo.tv_usec = timeout % 1000;
  50. if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)) == -1)
  51. {
  52. printf("ip:%s,setsockopt error\n",ips);
  53. return ERROR;
  54. }
  55. char sendpacket[PACKET_SIZE];
  56. char recvpacket[PACKET_SIZE];
  57. // 设定Ping包
  58. memset(sendpacket, 0, sizeof(sendpacket));
  59. pid_t pid;
  60. // 取得PID,作为Ping的Sequence ID
  61. pid=getpid();
  62. struct ip *iph;
  63. struct icmp *icmp;
  64. icmp=(struct icmp*)sendpacket;
  65. icmp->icmp_type=ICMP_ECHO;  //回显请求
  66. icmp->icmp_code=0;
  67. icmp->icmp_cksum=0;
  68. icmp->icmp_seq=0;
  69. icmp->icmp_id=pid;
  70. tval= (struct timeval *)icmp->icmp_data;
  71. gettimeofday(tval,NULL);
  72. icmp->icmp_cksum=cal_chksum((unsigned short *)icmp,sizeof(struct icmp));  //校验
  73. int n;
  74. // 发包
  75. n = sendto(sockfd, (char *)&sendpacket, sizeof(struct icmp), 0, (struct sockaddr *)&addr, sizeof(addr));
  76. if (n < 1)
  77. {
  78. printf("ip:%s,sendto error\n",ips);
  79. return ERROR;
  80. }
  81. // 接受
  82. // 由于可能接受到其他Ping的应答消息,所以这里要用循环
  83. while(1)
  84. {
  85. // 设定TimeOut时间,这次才是真正起作用的
  86. FD_ZERO(&readfds);
  87. FD_SET(sockfd, &readfds);
  88. maxfds = sockfd + 1;
  89. n = select(maxfds, &readfds, NULL, NULL, &timeo);
  90. if (n <= 0)
  91. {
  92. printf("ip:%s,Time out error\n",ips);
  93. close(sockfd);
  94. return ERROR;
  95. }
  96. // 接受
  97. memset(recvpacket, 0, sizeof(recvpacket));
  98. int fromlen = sizeof(from);
  99. n = recvfrom(sockfd, recvpacket, sizeof(recvpacket), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen);
  100. if (n < 1) {
  101. break;
  102. }
  103. char *from_ip = (char *)inet_ntoa(from.sin_addr);
  104. // 判断是否是自己Ping的回复
  105. if (strcmp(from_ip,ips) != 0)
  106. {
  107. printf("NowPingip:%s Fromip:%s\nNowPingip is not same to Fromip,so ping wrong!\n",ips,from_ip);
  108. return ERROR;
  109. }
  110. iph = (struct ip *)recvpacket;
  111. icmp=(struct icmp *)(recvpacket + (iph->ip_hl<<2));
  112. printf("ip:%s\n,icmp->icmp_type:%d\n,icmp->icmp_id:%d\n",ips,icmp->icmp_type,icmp->icmp_id);
  113. // 判断Ping回复包的状态
  114. if (icmp->icmp_type == ICMP_ECHOREPLY && icmp->icmp_id == pid)   //ICMP_ECHOREPLY回显应答
  115. {
  116. // 正常就退出循环
  117. break;
  118. }
  119. else
  120. {
  121. // 否则继续等
  122. continue;
  123. }
  124. }
  125. int main()
  126. {
  127. char cPing[16];
  128. printf("Please input ping IP:");
  129. scanf("%s",cPing);
  130. if(ping(cPing,10000))
  131. {
  132. printf("Ping succeed!\n");
  133. }
  134. else
  135. {
  136. printf("Ping wrong!\n");
  137. }
  138. }

测试结果:

root@an-virtual-machine:~/wyz/test# ./testping
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网络监测功能的更多相关文章

  1. ICMP 协议仿真及ping命令用途

    1.实验目的 加深对 IPv4 协议首部各定义域的理解,掌握路由表的结构和基本配置命令,熟悉 ICMP 的调试操作. 2.实验原理 IPv4 协议定义,网络层协议的相关 RFC 定义和描述. 3.实验 ...

  2. 002.ICMP--拼接ICMP包,实现简单Ping程序(原始套接字)

    一.大致流程: 将ICMP头和时间数据设置好后,通过创建好的原始套接字socket发出去.目的主机计算效验和后会将数据原样返回,用当前时间和返回的数据结算时间差,计算出rtt. 二.数据结构: ICM ...

  3. ICMP协议、DNS、ARP协议、ping、DHCP协议

    1.ICMP协议 1)ICMP协议,即:网络控制消息协议(Internet Control Message Protocol) 2)ICMP是网络层协议,因为ICMP报文是装在IP数据报中,作为它的数 ...

  4. 三、ARP协议和ICMP协议

    一.ARP协议 网络设备有数据要发送到另一台网络设备时,必须要知道对方的网络层地址(IP).IP地址由网络层来提供,但是仅有IP地址是不够的,IP数据报文必须封装成帧才能通过数据链路进行发送.数据帧必 ...

  5. (转)协议森林06 瑞士军刀 (ICMP协议)

    协议森林06 瑞士军刀 (ICMP协议) 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 到现在为止,我们讲解了网络层中最重要的I ...

  6. UNIX网络编程——利用ARP和ICMP协议解释ping命令

    一.MTU 以太网和IEEE 802.3对数据帧的长度都有限制,其最大值分别是1500和1492字节,将这个限制称作最大传输单元(MTU,Maximum Transmission Unit)      ...

  7. 【网络协议】ICMP协议、Ping、Traceroute

        ICMP协议 ICMP常常被觉得是IP层的一个组成部分,它是网络层的一个协议.它传递差错报文以及其它须要注意的信息.ICMP报文通常被IP层或更高层(TCP.UDP等)使用,它是在IP数据报内 ...

  8. PING的原理以及ICMP协议

    主要内容: 1.ping的原理以及工作过程 2.ICMP协议 3.ICMP的应用:ping,traceroute 1.ping的原理以及工作过程  ping的原理  ping 程序是用来探测主机到主机 ...

  9. 4.ICMP协议,ping和Traceroute

    1.IMCP协议介绍 前面讲到了,IP协议并不是一个可靠的协议,它不保证数据被送达,那么,自然的,保证数据送达的工作应该由其他的模块来完成.其中一个重要的模块就是ICMP(网络控制报文)协议. 当传送 ...

随机推荐

  1. DevOps之Pipeline集成junit、jacoco、SonarQube(二)

    一.准备工作 1.准备一个持续集成的代码工程 工程下载地址: Github地址为:https://github.com/zbbkeepgoing/springboot-demo 2.springboo ...

  2. 自定义 Swiper 的pageControl

    .part5-bg .swiper2 .swiper-pagination2{ bottom: 0.4rem; } /*未选中的小圆点样式*/ .part5-bg .swiper2 .swiper-p ...

  3. <label>标签的相关内容

    ㈠<label>标签的定义与用法 ⑴<label> 标签为 input 元素定义标注(标记). ⑵label 元素不会向用户呈现任何特殊效果.不过,它为鼠标用户改进了可用性.如 ...

  4. Python初记

    ------Python是一个优雅的大姐姐 我是通过<老男孩Python>学习Python,根据我手上的资源学习Python,资料不齐,但是这个是最好的,边学习边寻找有没有相同的类型. 在 ...

  5. MCMC & 贝叶斯

    用MCMC做参数估计

  6. Linux命令-磁盘管理(一)

    Linux命令-磁盘管理(一) Linux cd命令 Linux cd命令用于切换当前工作目录至 dirName(目录参数). 其中 dirName 表示法可为绝对路径或相对路径.若目录名称省略,则变 ...

  7. js多种方法取数组的最后一个元素

    一: pop()方法 pop()方法,删除数组最后一个并返回该元素 利用这个方法可以取到数组的最后一个,同理shift()可以取到数组的第一个(shift()删除数组第一个并返回该元素) var ar ...

  8. iview简单使用+按需加载组件的方法(全局和局部)

    1,简单使用 vue项目中使用iview非常简单: 首先安装依赖: $ npm install iview --save 会安装最新版本的依赖,安装完成后package.json会出现如下图配置 表示 ...

  9. Atcoder ARC101 E 树dp

    https://arc101.contest.atcoder.jp/tasks/arc101_c 题解是也是dp,好像是容斥做的,但是看不懂,而且也好像没讲怎么变n^2,看了写大佬的代码,自己理解了一 ...

  10. 如何使用git工具

    首先需要下载安坐git工具 地址如下:https://git-scm.com/downloads 安装完毕之后,就可以进入提供的命令行窗口 然后就可以使用了,比如:想从 github 克隆项目下来 g ...