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. buuctf@warmup_csaw_2016

    from pwn import * io=remote('node3.buuoj.cn',27774) io.recvuntil('WOW:') addr=(io.recvuntil('\n')[:- ...

  2. Java架构师面试题——JVM性能调优

    JVM内存调优 对JVM内存的系统级的调优主要的目的是减少GC的频率和Full GC的次数. 1.Full GC 会对整个堆进行整理,包括Young.Tenured和Perm.Full GC因为需要对 ...

  3. js-10s倒计时后关闭窗口

    效果: html: <h1 id="h1">10s后关闭窗口</h1> <a id="a1">启动</a> js ...

  4. C# 匿名对象 增加属性

    dynamic data = new System.Dynamic.ExpandoObject(); IDictionary<string, object> dictionary = (I ...

  5. git branch查看不到分支的名字解决办法

    git branch查看不到分支的名字解决办法 <!-- 1. 先初始化 --> git init; <!-- 2. 接着创建瑶瑶的专属分支 --> git checkout ...

  6. create-react-app 构建的项目使用 css module 方式来书写 css

    先 yarn eject 释放出来配置文件具体参见我之前写过相关的文章(这里不再重复), 找到 config 文件夹下的文件如下图所示: 找到如图所示的配置: 书写 css 的文件名例如(App.mo ...

  7. pyqt5对用qt designer设计的窗体实现弹出子窗口的示例

    pyqt5对用qt designer设计的窗体实现弹出子窗口的示例 脚本专栏 python 1. 用qt designer编写主窗体,窗体类型是MainWindow,空白窗口上一个按钮.并转换成mai ...

  8. linux 文件目录介绍

    网上的资源 太多了,copy 过来 留给自己用吧! 摘自 : http:/ 使用linux也有一年多时间了  最近也是一直在维护网站系统主机  下面是linux目录结构说明 本人使用的是centos系 ...

  9. Miniui 表单验证

    自定义表单验证: input输入框的表单验证可通过vtype和onvalidation事件两种方式实现 可编辑列表(例如div)的表单验证只能通过vtye来实现表单验证 (1)vtype方式: jsp ...

  10. centos6 yum安装mysql 5.6 (完整版)

    使用源代码编译安装mysql还是比较麻烦,一般来说设备安装时请网络同事临时开通linux上网,通过yum网络实现快速安装,或配置yum仓库进行内网统一安装. 通过网络快速安装过程如下 一.检查系统是否 ...