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. 2019ICPC南京网络赛总结

    这次是在学校打的,总体不算好,过两题校排200多..很惨. 开场一段时间没人过题,但是很多人交I, 我也就再看,看着看着发现不可做,这时候转F,花了半天读懂题意的时候想到主席树查找.但是主席树这种查找 ...

  2. JavaScript基础——JavaScript入门(笔记)

    JavaScript入门(笔记) JavaScript是一种轻量级.解释型的Web开发语言,该语言系统不是很庞杂,简单易学.由于所有现代浏览器都已嵌入JavaScript引擎,JavaScript源代 ...

  3. C# 遍历控件名称

    List<string> list = new List<string>(); list.Add("textBox2"); list.Add("t ...

  4. 在qt的QOpenGLWidget开启opengl的抗锯齿

    在QOpenGLWidget的构造函数添加下面几句代码即可 QSurfaceFormat surfaceFormat; surfaceFormat.setSamples();//多重采样 setFor ...

  5. cordova打包项目下载gradle失败

    在使用cordova打包项目的时候有时会因为网络环境原因导致下载gradle失败的情况,个人找到两种解决方案. 方案一: 根据报错的提示选择要下载的gradle去浏览器中下载,然后将gradle压缩包 ...

  6. POJ 2195 一人一房 最小费用流 建图 水题

    Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 21010   Accepted: 10614 Desc ...

  7. sh_02_del关键字

    sh_02_del关键字 name_list = ["张三", "李四", "王五"] # (知道)使用 del 关键字(delete)删除 ...

  8. 【CF963C】Cutting Rectangle(数论,构造,map)

    题意: 思路:考虑构造最小的单位矩形然后平铺 单位矩形中每种矩形的数量可以根据比例算出来,为c[i]/d,其中d是所有c[i]的gcd,如果能构造成功答案即为d的因子个数 考虑如果要将两种矩形放在同一 ...

  9. BZOJ 5326 [JSOI2017]博弈 (模拟费用流、线段树)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=5326 题解 终于成为第8个A掉这题的人--orz tzw神仙早我6小时 本以为这东西常数 ...

  10. 微信小程序_(组件)form表单

    Form表单.switch开关.数值选择器效果 官方文档:传送门 点击提交表单(按钮,提交开关,数值选择器,输入文本中)的值,显示在控制台上,点击重置,重置表单中的值. 实现过程 form表单,添加f ...