背景:

想实现一个在没外网的时候就自动重启路由器的功能。

又不想用ping命令,因为在代码里调用system("ping"); 可能会比较耗时,得单开线程。于是找了个实现ICMP协议的代码。

参考:https://blog.csdn.net/qivan/article/details/7237051

代码:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <netdb.h>
#include <string.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); #if 1
int sockfd;
// 取得socket 。 如果没加sudo 这里会报错
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);
printf("recvfrom Len:%d\n",n);
if (n < 1)
{
return ERROR;
} char *from_ip = (char *)inet_ntoa(from.sin_addr);
// 判断是否是自己Ping的回复
if (strcmp(from_ip,ips) != 0)
{
printf("NowPingip:%s Fromip:%s NowPingip 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,icmp->icmp_type:%d,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回显应答
{
// 正常就退出循环
printf("icmp succecss ............. \n");
break;
}
else
{
// 否则继续等
continue;
}
}
#endif
return SUCCESS;
} int main()
{
#if 1
char cPing[16];
printf("Please input ping IP:");
scanf("%s",cPing);
#else
char *cPing = "192.168.1.200";
#endif
if(ping(cPing,10000))
{
printf("Ping succeed!\n");
}
else
{
printf("Ping wrong!\n");
} return 0;
}

实际效果:

补充说明:

0)直接用参考链接上的代码时编译不过,不知道是不是因为我用的是cpp,没太深究。

1)实际使用的时候需要加上sudo,不然在创建套接字那个地方会报错。我还没想好怎么在代码里用sudo,(因为实际项目运行起来是不需要加sudo的)。

Linux C++ 实现一个简易版的ping (也就是imcp协议)的更多相关文章

  1. .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”

    FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...

  2. 依赖注入[5]: 创建一个简易版的DI框架[下篇]

    为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架.在<依赖注入[4]: 创建一个简易版的DI框架[上篇]> ...

  3. 依赖注入[4]: 创建一个简易版的DI框架[上篇]

    本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章(<控制反转>.<基于IoC的设计模式>和< 依赖注入模式>)从纯理论的角度 ...

  4. .NET CORE学习笔记系列(2)——依赖注入[4]: 创建一个简易版的DI框架[上篇]

    原文https://www.cnblogs.com/artech/p/net-core-di-04.html 本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章从 ...

  5. 手动实现一个简易版SpringMvc

    版权声明:本篇博客大部分代码引用于公众号:java团长,我只是在作者基础上稍微修改一些内容,内容仅供学习与参考 前言:目前mvc框架经过大浪淘沙,由最初的struts1到struts2,到目前的主流框 ...

  6. 如何实现一个简易版的 Spring - 如何实现 Setter 注入

    前言 之前在 上篇 提到过会实现一个简易版的 IoC 和 AOP,今天它终于来了...相信对于使用 Java 开发语言的朋友们都使用过或者听说过 Spring 这个开发框架,绝大部分的企业级开发中都离 ...

  7. 如何实现一个简易版的 Spring - 如何实现 Constructor 注入

    前言 本文是「如何实现一个简易版的 Spring」系列的第二篇,在 第一篇 介绍了如何实现一个基于 XML 的简单 Setter 注入,这篇来看看要如何去实现一个简单的 Constructor 注入功 ...

  8. 如何实现一个简易版的 Spring - 如何实现 @Component 注解

    前言 前面两篇文章(如何实现一个简易版的 Spring - 如何实现 Setter 注入.如何实现一个简易版的 Spring - 如何实现 Constructor 注入)介绍的都是基于 XML 配置文 ...

  9. 使用 js 和 Beacon API 实现一个简易版的前端埋点监控 npm 包

    使用 js 和 Beacon API 实现一个简易版的前端埋点监控 npm 包 前端监控,埋点,数据收集,性能监控 Beacon API https://caniuse.com/beacon 优点,请 ...

随机推荐

  1. TCP/IP详解 读书笔记:TCP:传输控制协议

    TCP的服务 TCP为应用层提供一种面向连接的.可靠的字节流服务. 一个TCP连接中,仅有两方进行彼此通信,所以广播和多播不能用于TCP. TCP通过以下方式提供可靠性: 应用数据被切割为TCP认为最 ...

  2. TCP/IP详解 读书笔记(一):概述

    分层 网络协议通常分不同层次进行开发,每一层负责不同的职责,一个协议簇指的是一组不同层次上的多个协议的组合. TCP/IP通常被认为是一个四层协议系统: 链路层:主要是处理与电缆或其他传输媒介的物理接 ...

  3. 解决Chrome94之后非安全网站请求localhost报CORS问题

    问题 自从谷歌浏览器升级到chrome94版本后,在非安全网站下通过请求本地接口就会出现以下错误: Access to XMLHttpRequest at 'http://127.0.0.1:1000 ...

  4. VMware vSphere,ESXi和vCenter的关系和区别

    VMware Inc.是一家软件公司.它开发了很多产品,尤其是各种云解决方案 .他的云解决方案包括云产品,数据中心产品和桌面产品等. vSphere是在数据中心产品下的一套软件.vSphere类似微软 ...

  5. MTK sensor 架构

    mtk architactureAP和scp 两部分组成从上到下的整体的结构是 app -->framerwork-->native-->hal -->kernel --> ...

  6. IP网络主动测评系统——IT运维人员的好帮手

    一.前 言 随着计算机网络的普及和快速发展,互联网已经融入到人们的衣食住行等方方面 面,如工作.购物.音视频聊天.视频会议.朋友圈.抖音.在线网游.网络电影 电视等.毫不夸张地说,现如今大部分人的绝大 ...

  7. 学习Spring5必知必会(6)~Spring DAO

    一.Spring 对持久层技术的支持 Spring DAO 1.模板类: 2.基类: 二.spring JDBC [JDBCTemplate 模板类] 1.案例:使用jdbc 完成crud操作 (1) ...

  8. 深度测评,商业智能BI、报表工具谁更好用?

    在很多人入门数据分析师或者投身大数据行业的时候,必然会听到的两个词就是"报表工具"和"BI商业智能"."BI"一词已被更广泛地知晓,但提起B ...

  9. 『无为则无心』Python基础 — 63、Python中的生成器

    目录 1.为什么要有生成器 2.创建生成器 (1)简单创建生成器 (2)生成器的使用 3.yield关键词 (1)yield关键词说明 (2)send()方法说明 4.使用yield实现斐波那契数列 ...

  10. prometheus k8s服务发现

    Prometheus的服务发现在解决什么问题? 被监控的目标(target)是整个监控体系中重要组成部分,传统监控系统zabbix通过 网络发现的机制自动创建主机到zabbix-server,进而快速 ...