arm linux c/c++实现ping网络测试

附源码:ping.cpp ping.h    是类的实现。

实例代码是从项目的应用中剥离出来的:

ping.cpp:

#include "ping.h"

Ping::Ping() {
	m_maxPacketSize = 4;
	m_datalen = 56;
	m_nsend = 0;
	m_nreceived = 0;
	m_icmp_seq = 0;
}

/*校验和算法*/
unsigned short Ping::getChksum(unsigned short *addr,int len)
{   
	int nleft=len;
	int sum=0;
	unsigned short *w=addr;
	unsigned short answer=0;

	/*把ICMP报头二进制数据以2字节为单位累加起来*/
	while(nleft>1)
	{   
		sum+=*w++;
		nleft-=2;
	}
	/*若ICMP报头为奇数个字节,会剩下最后一字节。把最后一个字节视为一个2字节数据的高字节,这个2字节数据的低字节为0,继续累加*/
	if( nleft==1)
	{   
		*(unsigned char *)(&answer)=*(unsigned char *)w;
		sum+=answer;
	}
	sum=(sum>>16)+(sum&0xffff);
	sum+=(sum>>16);
	answer=~sum;
	return answer;
}

/*设置ICMP报头*/
int Ping::packIcmp(int pack_no, struct icmp* icmp)
{   
	int i,packsize;
	struct icmp *picmp;
	struct timeval *tval;

	picmp = icmp;
	picmp->icmp_type=ICMP_ECHO;
	picmp->icmp_code=0;
	picmp->icmp_cksum=0;
	picmp->icmp_seq=pack_no;
	picmp->icmp_id= m_pid;
	packsize= 8 + m_datalen;
	tval= (struct timeval *)icmp->icmp_data;
	gettimeofday(tval,NULL);    /*记录发送时间*/
	picmp->icmp_cksum=getChksum((unsigned short *)icmp,packsize); /*校验算法*/
	return packsize;
}

/*剥去ICMP报头*/
bool Ping::unpackIcmp(char *buf,int len, struct IcmpEchoReply *icmpEchoReply)
{   
	int i,iphdrlen;
	struct ip *ip;
	struct icmp *icmp;
	struct timeval *tvsend, tvrecv, tvresult;
	double rtt;

	ip = (struct ip *)buf;
	iphdrlen = ip->ip_hl << 2;    /*求ip报头长度,即ip报头的长度标志乘4*/
	icmp = (struct icmp *)(buf + iphdrlen);  /*越过ip报头,指向ICMP报头*/
	len -= iphdrlen;            /*ICMP报头及ICMP数据报的总长度*/
	if(len < 8)                /*小于ICMP报头长度则不合理*/
	{   
		printf("ICMP packets\‘s length is less than 8\n");
		return false;
	}
	/*确保所接收的是我所发的的ICMP的回应*/
	if( (icmp->icmp_type==ICMP_ECHOREPLY) && (icmp->icmp_id == m_pid) )
	{   

		tvsend=(struct timeval *)icmp->icmp_data;
		gettimeofday(&tvrecv,NULL);  /*记录接收时间*/
		tvresult = tvSub(tvrecv, *tvsend);  /*接收和发送的时间差*/
		rtt=tvresult.tv_sec*1000 + tvresult.tv_usec/1000;  /*以毫秒为单位计算rtt*/
		icmpEchoReply->rtt = rtt;
		icmpEchoReply->icmpSeq = icmp->icmp_seq;
		icmpEchoReply->ipTtl = ip->ip_ttl;
		icmpEchoReply->icmpLen = len;
		return true;
	}
	else {
		return false;
	}
}

/*两个timeval结构相减*/
struct timeval Ping::tvSub(struct timeval timeval1,struct timeval timeval2)
{ 
	struct timeval result;
	result = timeval1;
	if (result.tv_usec < timeval2.tv_usec < 0)
	{    
		--result.tv_sec;
		result.tv_usec += 1000000;
	}
	result.tv_sec -= timeval2.tv_sec;
	return result;
}

/*发送三个ICMP报文*/
bool Ping::sendPacket()
{   
	size_t packetsize;
	while( m_nsend < m_maxPacketSize)
	{   
		m_nsend++;
		m_icmp_seq++;
		packetsize = packIcmp(m_icmp_seq, (struct icmp*)m_sendpacket); /*设置ICMP报头*/

		if(sendto(m_sockfd,m_sendpacket, packetsize, 0, (struct sockaddr *) &m_dest_addr, sizeof(m_dest_addr)) < 0  )
		{   
			perror("sendto error");
			continue;
		}
	}
	return true;
}

/*接收所有ICMP报文*/
bool Ping::recvPacket(PingResult &pingResult)
{       
	int len;
	extern int errno;
	struct IcmpEchoReply icmpEchoReply;
	int maxfds = m_sockfd + 1;
	int nfd  = 0;
	fd_set rset;     
	FD_ZERO(&rset);
	socklen_t fromlen = sizeof(m_from_addr);
	struct timeval timeout;
	timeout.tv_sec = 4;
	timeout.tv_usec = 0;

	for (int recvCount = 0; recvCount < m_maxPacketSize; recvCount++) 
	{   
		//printf("begin recv\n");
		FD_SET(m_sockfd, &rset);
		if ((nfd = select(maxfds, &rset, NULL, NULL, &timeout)) == -1) {             
			perror("select error");
			continue;   
		}
		if (nfd == 0) {
			//recv time out 
			//printf("request timeout\n");
			icmpEchoReply.isReply = false;
			pingResult.icmpEchoReplys.push_back(icmpEchoReply);
			continue;
		}
		if (FD_ISSET(m_sockfd, &rset)) {
			if( (len = recvfrom(m_sockfd, m_recvpacket,sizeof(m_recvpacket),0, (struct sockaddr *)&m_from_addr,&fromlen)) <0)
			{	   
				if(errno==EINTR)
					continue;
				perror("recvfrom error");
				continue;
			}
			icmpEchoReply.fromAddr = inet_ntoa(m_from_addr.sin_addr) ;
			if (icmpEchoReply.fromAddr != pingResult.ip) {
				//printf("invalid address, discard\n");
				//retry again
				recvCount--;
				continue;
			}
		}
		if(unpackIcmp(m_recvpacket, len, &icmpEchoReply)==-1) {
			//retry again
			recvCount--;
			continue;
		}
		icmpEchoReply.isReply = true;
		pingResult.icmpEchoReplys.push_back(icmpEchoReply);
		m_nreceived++;
	}
	return true;
}

bool Ping::getsockaddr(const char * hostOrIp, struct sockaddr_in* sockaddr) {
	struct hostent *host;
	struct sockaddr_in dest_addr;
	unsigned long inaddr=0l;
	bzero(&dest_addr,sizeof(dest_addr));
	dest_addr.sin_family=AF_INET;
	/*判断是主机名还是ip地址*/
	if( inaddr=inet_addr(hostOrIp)==INADDR_NONE)
	{    
		if((host=gethostbyname(hostOrIp))==NULL) /*是主机名*/
		{   
			//printf("gethostbyname error:%s\n", hostOrIp);
			return false;
		}
		memcpy( (char *)&dest_addr.sin_addr,host->h_addr,host->h_length);
	}
	/*是ip地址*/
	else if (!inet_aton(hostOrIp, &dest_addr.sin_addr)){  
		//memcpy( (char *)&dest_addr,(char *)&inaddr,host->h_length);
		//fprintf(stderr, "unknow host:%s\n", hostOrIp);
		return false;
	}
	*sockaddr = dest_addr;
	return true;
}
bool Ping::ping(std::string host, PingResult& pingResult) {
	return ping(host, 1, pingResult);
}

bool Ping::ping(std::string host, int count, PingResult& pingResult) {
	struct protoent *protocol;
	int size = 50 * 1024;
	IcmpEchoReply icmpEchoReply;
	bool ret;

	m_nsend = 0;
	m_nreceived = 0;
	pingResult.icmpEchoReplys.clear();
	m_maxPacketSize = count;
	m_pid = getpid();

	pingResult.dataLen = m_datalen;

//	if( (protocol = getprotobyname("icmp") )==NULL)
//	{
//		perror("getprotobyname");
//		return false;
//	}
	/*生成使用ICMP的原始套接字,这种套接字只有root才能生成*/
//	if( (m_sockfd=socket(AF_INET,SOCK_RAW,protocol->p_proto) )<0)
//	{
//		//perror("socket error");
//		extern int errno;
//		pingResult.error = strerror(errno);
//		return false;
//	}
    if ((m_sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP))<0)
    {
        perror("socket error");
    }
	/*扩大套接字接收缓冲区到50K这样做主要为了减小接收缓冲区溢出的
	  的可能性,若无意中ping一个广播地址或多播地址,将会引来大量应答*/
	setsockopt(m_sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size) );

	/*获取main的进程id,用于设置ICMP的标志符*/
	if (!getsockaddr(host.c_str(), &m_dest_addr)) {
		pingResult.error = "unknow host " + host;
		return false;
	}
	pingResult.ip = inet_ntoa(m_dest_addr.sin_addr);
	sendPacket();  /*发送所有ICMP报文*/
	recvPacket(pingResult);  /*接收所有ICMP报文*/
	pingResult.nsend = m_nsend;
	pingResult.nreceived = m_nreceived;
	close(m_sockfd);
	return true;

}

ping.h

#ifndef PING_H
#define PING_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <setjmp.h>
#include <errno.h>

#include <string>
#include <vector>
#define PACKET_SIZE     4096
#define MAX_WAIT_TIME   5
#define MAX_NO_PACKETS  3

struct IcmpEchoReply {
	int icmpSeq;
	int icmpLen;
	int ipTtl;
	double rtt;
	std::string fromAddr;
	bool isReply;
};
struct PingResult {
	int dataLen;
	int nsend;
	int nreceived;
	std::string ip;
	std::string error;
	std::vector<IcmpEchoReply> icmpEchoReplys;
};

class Ping {
	public:
		Ping();
		bool ping(std::string host, PingResult &pingResult);
		bool ping(std::string host, int count, PingResult& pingResult);
	private:
		unsigned short getChksum(unsigned short *addr,int len);
		int packIcmp(int pack_no, struct icmp* icmp);
		bool unpackIcmp(char *buf,int len, struct IcmpEchoReply *icmpEchoReply);
		struct timeval tvSub(struct timeval timeval1,struct timeval timval2);
		bool getsockaddr(const char * hostOrIp, sockaddr_in* sockaddr);
		bool sendPacket();
		bool recvPacket(PingResult &pingResult);
	private:
		char m_sendpacket[PACKET_SIZE];
		char m_recvpacket[PACKET_SIZE];
		int m_maxPacketSize;
		int m_sockfd;
		int m_datalen;
		int m_nsend;
		int m_nreceived;
		int m_icmp_seq;
		struct sockaddr_in m_dest_addr;
		struct sockaddr_in m_from_addr;
		pid_t m_pid;
};
#endif

实例代码:

        if ( eth == false )
        {
            char * hostOrIp =  "192.168.1.20";
            int nsend = 0, nreceived = 0;
            bool ret;
            PingResult pingResult;
            Ping ping = Ping();
            for (int count = 1; count <= 4; count++)
            {
                ret = ping.ping(hostOrIp, 1, pingResult);
                if (count == 1)
                {
                    printf("PING %s(%s): %d bytes data in ICMP packets.\n", hostOrIp, pingResult.ip.c_str(), pingResult.dataLen);
                }
                if (!ret)
                {
                    printf("%s\n", pingResult.error.c_str());
                    break;
                }
                showPingResult(pingResult);
                nsend += pingResult.nsend;
                nreceived += pingResult.nreceived;
            }
            if (ret)
            {
                printf("%d packets transmitted, %d received , %%%d lost\n", nsend, nreceived,
                    (nsend - nreceived) / nsend * 100);
                eth = true;
                system("echo 0 > /sys/class/gpio/gpio230/value");   // 灯6
            }
            else
            {
                printf("-----------------eth0 failed--------------\n");
                eth = false;
                system("echo 1 > /sys/class/gpio/gpio230/value");   // 灯6
            }
        }
时间: 2024-11-03 21:58:28

arm linux c/c++实现ping网络测试的相关文章

arm linux 启动之二:start_kernel到创建1号进程

本文介绍arm linux启动的第二部分,C语言编写,主要讲述start_kernel到1号进程的创建.主要讲述大概过程,以后再对子函数进行讲解. 一.start_kernel start_kernel位于init/main.c,主要完成linux一些子系统的初始化. 1)smp_setup_processor_id() 单CPU位为空. 2)lock_kernel() 锁CPU,linux是支持抢占的,多CPU时调用这个函数防止其他CPU抢占.3)tick_init() 时间相关初始化4)bo

ARM Linux从Bootloader、kernel到filesystem启动流程

转自:http://www.veryarm.com/1491.html ARM Linux启动流程大致为:bootloader ---->kernel---->root filesystem.bootloader 是一上电就拿到cpu 的控制权的,而bootloader实现了硬件的初始化.bootloader俨然就成了Power on 之后”第一个吃螃蟹”的代码. 谈到这就得想到硬件机制是如何满足这个功能的了.CPU内部一般都集成小容量的SRAM (又叫stapping stone,垫脚石),

python实战系列之批量主机ping网络测试(07)

1.需求说明   工作环境中,经常会有使用到ping对网络上的主机做网络测试,如机器上架,下线,测试等一些需要,对于大批量的机器来说,逐个主机ping测试,显然难以满足要求,对于机器比较多的场景,可以将需要执行ping测试的IP地址存放至一个文件内,调用脚本执行网络测试,方便,便捷. 2.程序内容 vim ping.py  #!/usr/bin/env python #_*_ coding:utf8 _*_ #author: Happy #来自Happy试验试验 http://happylab.

ARM Linux 大小核切换 ——cortex-A7 big.LITTLE 大小核 切换代码分析

ARM Linux 大小核切换——cortex-A7 big.LITTLE 大小切换代码分析 8核CPU或者是更多核的处理器,这些CPU有可能不完全对称.有的是4个A15和4个A7,或者是4个A57和4个A53,甚至像海思麒麟935处理器(4核A53 2.2 GHz + 4核A53 1.5 GHz),这8个核的频率可能不一样,则使用过程中需要大小核切换(频率高的是大核,频率低的是小核).本文以ARM cortex-A7为例,分析大小核切换的代码,着重于分析实现切换的代码,对于为什么要这样切换.以

ARM linux电源管理——Cortex A系列CPU(32位)睡眠和唤醒的底层汇编实现

ARM linux电源管理——Cortex A系列CPU(32位)睡眠和唤醒的底层汇编实现 承接 http://www.wowotech.net/pm_subsystem/suspend_and_resume.html Linux电源管理(6)_Generic PM之Suspend功能一文中的下图. 本文主要分析平台相关的CPU睡眠和唤醒,即下电和上电流程,以及ARM底层汇编代码实现. 内核版本:3.1.0               CPU:ARM Cortex-A7 1 平台相关函数执行流程

Linux和Windows下ping命令详解

转:http://linux.chinaitlab.com/command/829332.html 一.Linux下的ping参数 用途 发送一个回送信号请求给网络主机. 语法 ping [ -d] [ -D ] [ -n ] [ -q ] [ -r] [ -v] [ \ -R ] [ -a addr_family ] [ -c Count ] [ -w timeout ] [ -f | -i \ Wait ] [ -l Preload ] [ -p Pattern ] [ -s PacketS

为arm linux交叉编译tcpdump

1.从官网www.tcpdump.org下载并解压源文件,这里是 tcpdump-4.5.1.tar.gz libpcap-1.5.3.tar.gz 2.编译libpcap,安装目录为/home/armroot,交叉编译不能确定pcap类型,手工指定为linux ./configure --host=arm-linux --with-pcap=linux --prefix=/home/armroot make make install 3.编译tcpdump.交叉编译不能确定内核版本,手工指定为

arm linux设置登录用户和用户密码,以及登录到root后reboot无法重启的问题

设置登录用户和用户密码 在/etc/inittab文件中,内容如下 #first:run the system script file ::sysinit:/etc/init.d/rcS #::askfirst:-/bin/sh ::sysinit:-/bin/login ::ctrlaltdel:-/sbin/reboot #umount all filesystem ::shutdown:/bin/umount -a -r #restart init process ::restart:/s

学习ARM+Linux的很好的资料(转)

前段时间做了一个关于ARM9 2440资料的汇总帖,很高兴看到***和CSDN等论坛朋友们的支持和鼓励.当年学单片机的时候datasheet和学习资料基本都是在论坛上找到的,也遇到很多好心的高手朋友,耐心的回答我提出的问题.感激.图报,很简单的想法.希望这次整理的资料帖能对更多的嵌入式爱好者朋友带来帮助! PS:    在此特别感谢 古道热肠 版主把我的帖子加精,给小弟极大鼓舞! 嵌入式入门篇: 什么是嵌入式系统                         http://www.helloa