Linux C++ 实现一个简易版的ping (也就是imcp协议)
背景:
想实现一个在没外网的时候就自动重启路由器的功能。
又不想用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协议)的更多相关文章
- .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”
FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...
- 依赖注入[5]: 创建一个简易版的DI框架[下篇]
为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架.在<依赖注入[4]: 创建一个简易版的DI框架[上篇]> ...
- 依赖注入[4]: 创建一个简易版的DI框架[上篇]
本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章(<控制反转>.<基于IoC的设计模式>和< 依赖注入模式>)从纯理论的角度 ...
- .NET CORE学习笔记系列(2)——依赖注入[4]: 创建一个简易版的DI框架[上篇]
原文https://www.cnblogs.com/artech/p/net-core-di-04.html 本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章从 ...
- 手动实现一个简易版SpringMvc
版权声明:本篇博客大部分代码引用于公众号:java团长,我只是在作者基础上稍微修改一些内容,内容仅供学习与参考 前言:目前mvc框架经过大浪淘沙,由最初的struts1到struts2,到目前的主流框 ...
- 如何实现一个简易版的 Spring - 如何实现 Setter 注入
前言 之前在 上篇 提到过会实现一个简易版的 IoC 和 AOP,今天它终于来了...相信对于使用 Java 开发语言的朋友们都使用过或者听说过 Spring 这个开发框架,绝大部分的企业级开发中都离 ...
- 如何实现一个简易版的 Spring - 如何实现 Constructor 注入
前言 本文是「如何实现一个简易版的 Spring」系列的第二篇,在 第一篇 介绍了如何实现一个基于 XML 的简单 Setter 注入,这篇来看看要如何去实现一个简单的 Constructor 注入功 ...
- 如何实现一个简易版的 Spring - 如何实现 @Component 注解
前言 前面两篇文章(如何实现一个简易版的 Spring - 如何实现 Setter 注入.如何实现一个简易版的 Spring - 如何实现 Constructor 注入)介绍的都是基于 XML 配置文 ...
- 使用 js 和 Beacon API 实现一个简易版的前端埋点监控 npm 包
使用 js 和 Beacon API 实现一个简易版的前端埋点监控 npm 包 前端监控,埋点,数据收集,性能监控 Beacon API https://caniuse.com/beacon 优点,请 ...
随机推荐
- 5道面试题,拿捏String底层原理!
原创:微信公众号 码农参上,欢迎分享,转载请保留出处. String字符串是我们日常工作中常用的一个类,在面试中也是高频考点,这里Hydra精心总结了一波常见但也有点烧脑的String面试题,一共5道 ...
- kubeadm + containerd 部署 k8s-v1.23.3(含证书升级)
文章目录 前言 环境准备 答应我,所有节点都要关闭防火墙 答应我,所有节点都要关闭selinux 答应我,所有节点都要关闭swap 答应我,所有节点都要开启内核模块 答应我,所有节点都要开启模块自动加 ...
- RFC2889MAC地址学习速率——网络测试仪实操
一.简介 RFC 2889为LAN交换设备的基准测试提供了方法学,它将RFC 2544中为网络互联设备基准测试所定义的方法学扩展到了交换设备,提供了交换机转发性能(Forwarding Perform ...
- 广州市首批!Smartbi入库信创产品资源池,引领国产BI软件崛起
为贯彻落实软件高质量发展战略,加快建设有影响力的信息技术创新(简称"信创")资源池,广州市工业和信息化局经征集申报.专家评审.现场考察等多个环节,发布了"广州市信息技术应 ...
- oracle 11g rac修改监听端口(远程监听和本地监听)
转至:https://www.cnblogs.com/yj411511/p/12459533.html 目录 1.修改远程监听端口 1.1 查看远程监听状态 1.2 修改SCAN listener端口 ...
- 使用PLSQL 创建Oracle数据库用户并设置权限
转至https://blog.csdn.net/ying890/article/details/14083029?utm_medium=distribute.pc_relevant_download. ...
- Pycharm新建Python项目
关于新建项目时配置项目环境(最好是每个项目单独的虚拟Python环境): Python为什么要使用虚拟环境-Python虚拟环境的安装和配置-virtualenv Pycharm创建Python项目 ...
- 矩池云上安装caffe gpu教程
选用CUDA10.0镜像 添加nvidia-cuda和修改apt源 curl -fsSL https://mirrors.aliyun.com/nvidia-cuda/ubuntu1804/x86_6 ...
- 测评 | 矩池云上架 RTX 2080 Ti 八卡机开箱
大家好,福利君今天给给大家带来的是一则消息.矩池云将上架了超微八卡GPU服务器,全新的机器组合,可靠的服务品质. 产品性能 在这里引用Lambda Labs基于FP32对多GPU扩展训练性能评测的数据 ...
- CSS简介,基础选择器,字体属性,文本属性
欢迎大家去博客冰山一树Sankey,浏览效果更好.直接右上角搜索该标题即可 博客园主页:博客园主页-冰山一树Sankey CSDN主页:CSDN主页-冰山一树Sankey 前端学习:学习地址:黑马程序 ...