ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Linux C++实现ping指令

2019-07-31 16:09:01  阅读:501  来源: 互联网

标签:addr int ping C++ tv Linux Cping icmp struct


//#include "ping.h"
#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>

#define PACKET_SIZE 4096
#define SEND_DATA_LEN 56
#define ERROR    -1
#define SUCCESS   1
#define MAX_WAIT_TIME 3
#define MAX_NO_PACKETS 4
#define NULL 0

using namespace std;

class Cping
{
	public:
		Cping(const char * ip, int timeout);
		Cping(const Cping& org);
		virtual ~Cping();
	
	private:
		std::string m_strIp;
		std::string m_copy_Ip;
		
		int m_nSend;
		int m_nRecv;
		struct sockaddr_in m_dest_addr;
		struct sockaddr_in m_from_addr;
		
		char m_sendpacket[PACKET_SIZE];
		char m_recvpacket[PACKET_SIZE];
		
		struct timeval m_tvrecv;
		struct timeval m_begin_tvrecv;
		struct timeval m_end_tvrecv;
		double m_dTotalResponseTimes;
		int m_nSocketfd;
		
		int m_nMaxTimeWait;
   public:
		bool ping(int times);
		bool CreateSocket();
		bool CloseSocket();
		
		void send_packet(void);
		void recv_packet(void);
		
		int pack(int pack_no);
		int unpack(char *buf, int len);
		
		void tv_sub(struct timeval *out, struct timeval *in);
		void statistics(int sig);
		
		static unsigned short cal_chksum(unsigned short *addr, int len);
};

Cping::Cping(const char *ip, int timeout)
{
	m_strIp = ip;
	m_copy_Ip = ip;
	
	m_nSend = 0;
	m_nRecv = 0;
	
	m_dTotalResponseTimes = 0;
	
	if(timeout > MAX_WAIT_TIME)
	{
		m_nMaxTimeWait = MAX_WAIT_TIME;
	}
	else
	{
		m_nMaxTimeWait = timeout;
	}
}

Cping::~Cping()
{
	if(!CloseSocket())
	{
		cout << "CloseSocket failed!" << endl;
	}
}

bool Cping::ping(int times)
{
	if(!CreateSocket())
	{
		printf("CreateSocket failed!!!\n");
		return false;
	}
	printf("PING %s(%s): %d bytes data in ICMP packets.\n", m_strIp.c_str(),
					m_copy_Ip.c_str(), SEND_DATA_LEN);
	while(times--)
	{
		send_packet();
		recv_packet();
		sleep(1);
	}
	statistics(SIGINT);
	return true;
}

bool Cping::CreateSocket()
{
	char buf[2048];
	int errnop = 0;
	unsigned long inaddr;
	struct hostent hostinfo, *dest_phost;
	struct protoent *protocol = NULL;
	
	if((protocol = getprotobyname("icmp")) == NULL)
	{
		perror("getprotobyname()");
		printf("CreateSocket : getprotobyname failed:%d\n",errnop);
		return false;
	}
	if(-1 == (m_nSocketfd = socket(AF_INET,SOCK_RAW,protocol->p_proto)))
	{
		perror("socket");
		printf("CreateSocket: create socket failed:%d\n", m_nSocketfd);
		return false;
	}
	setuid(getuid());
	m_dest_addr.sin_family = AF_INET;
	
	bzero(&(m_dest_addr.sin_zero),8);
	
	if((inaddr = inet_addr(m_strIp.c_str())) == INADDR_NONE)
	{
		//if(getprotobyname_r(m_strIp.c_str(), &hostinfo, buf, sizeof(buf), &dest_phost, &errnop))
		//{
		//	printf("CreateSocket: getprotobyname error %s failed:%d\n", m_strIp.c_str(),errnop);
		//	return false;
		//}
		//else
		//{
			m_dest_addr.sin_addr = *((struct in_addr *)dest_phost->h_addr); 
		//}
	}
	else
	{
		m_dest_addr.sin_addr.s_addr = inaddr;
	}
	
	m_copy_Ip = inet_ntoa(m_dest_addr.sin_addr);
	
	return true;
}

bool Cping::CloseSocket()
{
	bool flag = false;
	if(m_nSocketfd)
	{
		close(m_nSocketfd);
		flag = true;
	}
	return flag;
}

void Cping::send_packet(void)
{
	int packetsize;
	packetsize = pack(m_nSend);
	
	if((sendto(m_nSocketfd, m_sendpacket, packetsize, 0 ,(const struct sockaddr*)&m_dest_addr, sizeof(m_dest_addr))) < 0)
	{
		printf("send_packet: send error :\n");
	}
	m_nSend++;
}

void Cping::recv_packet(void)
{
	int fromlen, packetsize, n;
	while(m_nRecv < m_nSend)
	{
		struct timeval timeout;
		fd_set readfd;
		FD_ZERO(&readfd);
		
		FD_SET(m_nSocketfd, &readfd);
		
		int maxfd = m_nSocketfd + 1;
		timeout.tv_sec = m_nMaxTimeWait;
		
		timeout.tv_usec = 0;
		
		n = select(maxfd, &readfd, NULL, NULL, &timeout);
		
		switch(n)
		{
			case 0:
				printf("recv_packet: select time out: \n");
				break;
			case -1:
				printf("recv_packet: select error: \n");
				break;
			default:
				if(FD_ISSET(m_nSocketfd, &readfd))
				{
					if((packetsize = recvfrom(m_nSocketfd, m_recvpacket, sizeof(m_recvpacket), 0,(struct sockaddr *)&m_from_addr,(socklen_t*)&fromlen)) < 0)
					{
						printf("packetsize = %d\n", packetsize);
						//printf("recv_packet: recv error: %d\n", errno);
						return ;
					}
					gettimeofday(&m_tvrecv, NULL);
					m_end_tvrecv.tv_usec = m_tvrecv.tv_usec;
					m_end_tvrecv.tv_sec = m_tvrecv.tv_sec;
					
					if(unpack(m_recvpacket, packetsize) == -1)
					{
						continue;
					}
					m_nRecv++;
				}
				break;
		}
	}
}

int Cping::pack(int pack_number)
{
	int packsize;
	struct icmp *pIcmp;
	struct timeval *pTime;
	
	pIcmp = (struct icmp*)m_sendpacket;
	
	pIcmp->icmp_type = ICMP_ECHO;
	pIcmp->icmp_code = 0;
	pIcmp->icmp_cksum = 0;
	pIcmp->icmp_seq = pack_number;
	pIcmp->icmp_id = getpid();
	packsize = 8 + SEND_DATA_LEN;
	pTime = (struct timeval *)pIcmp->icmp_data;
	gettimeofday(pTime, NULL);
	if(m_nSend == 0)
	{
		m_begin_tvrecv.tv_usec = pTime->tv_usec;
		m_begin_tvrecv.tv_sec = pTime->tv_sec;
	}
	pIcmp->icmp_cksum = cal_chksum((unsigned short*)pIcmp, packsize);
	return packsize;
}

int Cping::unpack(char *buf, int len)
{
	int i, iphdrlen;
	struct icmp *pIcmp;
	struct timeval *tvsend;
	struct ip* recv_ip = (struct ip*)buf;
	double rtt;
	
	iphdrlen = recv_ip->ip_hl << 2;
	pIcmp = (struct icmp*)(buf + iphdrlen);
	len -= iphdrlen;
	if(len < 8)
	{
		printf("ICMP packets's length is less than 8'");
		return -1;
	}
	
	if((pIcmp->icmp_type == ICMP_ECHOREPLY) && (m_copy_Ip == inet_ntoa(m_from_addr.sin_addr)) && (pIcmp->icmp_id = getpid()) )
	{
		tvsend = (struct timeval *)pIcmp->icmp_data;
		tv_sub(&m_tvrecv, tvsend);
		rtt = m_tvrecv.tv_sec * 1000 + (double)m_tvrecv.tv_usec / 1000;
		
		printf("%d byte from %s : icmp_seq=%u ttl=%d time=%.3fms\n",
			len,
			inet_ntoa(m_from_addr.sin_addr),
			pIcmp->icmp_seq,
			recv_ip->ip_ttl,
			rtt);
	}
	else
	{
		printf("throw away the old package %d\tbyte from %s\t: icmp_seq=%u\t: icmp_seq=%u\t ttl=%u\trtt=%.3f\tms",
		len,
		inet_ntoa(m_from_addr.sin_addr),
		pIcmp->icmp_seq,
		recv_ip->ip_ttl,
		rtt);
		return -1;
	}
	return 1;
}

void Cping::tv_sub(struct timeval *out, struct timeval *in)
{
	if((out->tv_usec -= in->tv_usec) < 0)
	{
		--out->tv_sec;
		out->tv_usec += 10000000;
	}
	out->tv_sec -= in->tv_sec;
}

void Cping::statistics(int sig)
{
	tv_sub(&m_end_tvrecv, &m_begin_tvrecv);
	m_dTotalResponseTimes = m_end_tvrecv.tv_sec * 1000 + (double)m_end_tvrecv.tv_usec / 1000;
	printf("--------statistics----------\n");
	printf("%d packets transmitted, %d received, %d%% lost, time: %.3lfms\n", m_nSend, m_nRecv,(m_nSend - m_nRecv) / m_nSend*100, m_dTotalResponseTimes);
	close(m_nSocketfd);
}

unsigned short Cping::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;
}

int main(int argc, char *argv[])
{
	Cping Ping(argv[1], 20);
	Ping.ping(3);
}

命名为 myping.cpp
编译命令:sudo g++ -o myping myping.cpp
修改权限:sudo chmod u+s myping
使用:./myping 192.168.1.222

标签:addr,int,ping,C++,tv,Linux,Cping,icmp,struct
来源: https://blog.csdn.net/CCCCxq/article/details/97925553

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有