通过ICMP协议测试目标主机是否在线
2014-11-28 16:31
211 查看
/* AliveChecker.h author: zhouciming@163.com */ #ifndef __ALIVE_CHECKER_H__ #define __ALIVE_CHECKER_H__ typedef unsigned short ushort; typedef unsigned long ulong; class CPing { public: CPing(); ~CPing(); bool ping(ulong destIP, int timeout = 10000); protected: bool init(); ushort getCheckSum(ushort* addr, int len); // 计算校验和 private: int m_sockfd; }; #endif
/*
AliveChecker.cpp
author: zhouciming@163.com
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <netinet/ip_icmp.h>
#include "AliveChecker.h"
#define INVALID_SOCKET -1
#define PACKET_SIZE 1024
CPing::CPing()
{
m_sockfd = INVALID_SOCKET;
}
CPing::~CPing()
{
if(m_sockfd != INVALID_SOCKET)
close(m_sockfd);
}
bool CPing::init() // 初始化socket fd
{
if(m_sockfd != INVALID_SOCKET)
close(m_sockfd);
m_sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (m_sockfd < 0)
{
perror("socket");
return false;
}
return true;
}
// 向目标地址发送一个icmp数据包, 并接收响应来判断目标主机是否在线
bool CPing::ping(ulong destIP, int time_out) // time_out: 超时时间(单位: 毫秒)
{
if(m_sockfd == INVALID_SOCKET && init() == false)
return false;
struct timeval timeout;
timeout.tv_sec = time_out / 1000; // 秒
timeout.tv_usec = (time_out % 1000) * 1000; // 微秒
if (setsockopt(m_sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) == -1)
{
perror("setsockopt");
return false;
}
struct icmp* icmp;
struct timeval *tval;
char sendpacket[PACKET_SIZE] = {0};
pid_t pid = getpid();
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 = getCheckSum((ushort*)icmp, sizeof(struct icmp));
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = destIP; // 设置目标地址
// 发送ICMP数据包
int n = sendto(m_sockfd, (char*)&sendpacket, sizeof(struct icmp), 0, (struct sockaddr*)&addr, sizeof(addr));
if (n < 1)
{
return false;
}
while(1) // 可能会接收到其他ping的应答消息, 所以这里用循环
{
int maxfds;
fd_set readfds;
struct sockaddr_in from;
int fromlen = sizeof(from);
char recvBuf[PACKET_SIZE] = {0};
FD_ZERO(&readfds);
FD_SET(m_sockfd, &readfds);
maxfds = m_sockfd + 1;
n = select(maxfds, &readfds, NULL, NULL, &timeout);
if (n <= 0)
{
return false;
}
n = recvfrom(m_sockfd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen);
if (n < 1)
{
break;
}
ulong fromIP = from.sin_addr.s_addr;
if (fromIP != destIP) // 不是目标主机的echo信息
{
return false;
}
struct ip* iph = (struct ip *)recvBuf;
icmp = (struct icmp *)(recvBuf + (iph->ip_hl << 2));
if (icmp->icmp_type == ICMP_ECHOREPLY && icmp->icmp_id == pid) // ICMP_ECHOREPLY回显应答
{
return true;
}
}
return false;
}
ushort CPing::getCheckSum(ushort* addr, int len)
{
int sum = 0;
ushort *w = addr;
ushort answer = 0;
while(len > 1)
{
sum += *w++;
len -= 2;
}
if( len == 1)
{
*(unsigned char *)(&answer) = *(unsigned char *)w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return answer;
}
/* main.cpp author: zhouciming@163.com */ #include <stdio.h> #include <arpa/inet.h> #include "AliveChecker.h" void test(const char* ip) { CPing ping; in_addr_t destIP = inet_addr(ip); if(ping.ping(destIP)) { printf("ping successful\n"); } else { printf("ping failed\n"); } } int main(int argc, char* argv[]) { if(argc < 2) { printf("Usage: %s <destIP>\n", argv[0]); return 1; } else { const char* ip = argv[1]; test(ip); } return 0; }
Makefile:
#CROSS = arm-hisiv100nptl-linux-
CXX = $(CROSS)g++
RM=rm -f
CFLAGS = -Wall -Os -DLINUX
ALL=a
all: $(ALL)
a: main.cpp AliveChecker.cpp
$(CXX) $(CFLAGS) -o $@ $^
clean:
$(RM) *.o $(ALL)
注意:以上编译出来的程序必须以root用户执行,因为ICMP协议用到了SOCK_RAW(原始套接字)。
相关文章推荐
- shell脚本实现批量测试局域网主机是否在线
- shell脚本实现批量测试局域网主机是否在线
- Zabbix通过ping监控主机主机是否在线
- linux:C语言通过ICMP协议判断局域网内部主机是否存活
- 测试主机是否在线的脚本
- tcpcopy---从IP层来截取请求,转发给目标测试服务器,达到在线压力甚至极限压力测试的目的
- java检测主机是否在线isReachable函数
- 不用软件直接查询QQ好友的IP地址(二) && 通过 Ping 得知对方是否联网在线(与QQ是否上线无关)
- 用 javascript 实现 ping 一个主机,仅测试是否能够连接。
- 通过获取DNS解析的未转义主机名,区分测试环境和正式环境代码
- 通过Js脚本来判断目标站点是否能打开!
- 严格的内网中通过curl来探测目标是否支持http协议
- 判断目标主机和自己是否是一个子网的方法
- wampserver下配置虚拟主机 实现多站点支持(测试通过WIN7 64)
- 用微软官网在线密码强度测试工具看看你的密码是否强壮
- SQL存储过程测试(6)——当待测存储过程返回行集的时候 如何判断测试结果是否通过
- VC判断目标主机是否存活,模拟系统的ping
- NAT连接虚拟机和主机的通信(静态IP配置完整图解,测试通过可用)--结束篇
- VC判断目标主机是否存活,模拟系统的ping
- [有人帮我说明了原因,明天找人测试一下]紧急求助!!(请您帮看看我的一个在线考试系统的部分代码是否有问题啊?)