ping多个IP地址的实现,检测局域网内存在的主机

从上一篇文章上改变过来,在linux下编译运行过,中间使用select实现无阻塞,
原始套接字要使用root权限
#include "slas_common.h"

#define MAX_WAIT_TIME 1
#define SEND_NUM	3
#define CONTENT		"abcdefghijkmn_abcdefghijkmn_abcdefghijkmn"
#define DATALEN		56
#define MAX_SIZE	1024

int pingsucc = 0;

void handler(int signo){
	pingsucc = 0;
}

void buf_hex_print(char* p, int len){
	unsigned char* line;
	int i; 
	int thisline;
	int offset;
	line = (unsigned char*)p;
	offset = 0;
	printf("buf_hex_print,len = [%u]\n", len);
	while (offset < len){
		printf("0x%04x ", offset);
		thisline = len - offset;
		if (thisline > 16){
			thisline = 16;
		}       
		for (i = 0; i < thisline; i++){
			printf("%02x ", line[i]);
		}       
		for (; i < 16; i++){
			printf("   ");
		}
		for (i = 0; i < thisline; i++){
			printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
		}
		printf("\n");
		offset += thisline;
		line += thisline;
	}
}

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

int unpack(char *buf,int len, struct timeval *tvrecv, struct sockaddr_in *from)
{
	int i,iphdrlen;
	struct ip *ip;
	struct icmp *icmp;
	struct timeval *tvsend;
	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 -1;
	}
	/*确保所接收的是我所发的的ICMP 的回应*/
	//printf("icmp type:%d, code:%d, pid:%d\n", icmp->icmp_type, icmp->icmp_code,icmp->icmp_id);
	if( (icmp->icmp_type == ICMP_ECHOREPLY) && (icmp->icmp_id == getpid()) )
	{
		tvsend=(struct timeval *)icmp->icmp_data;
		tv_sub(tvrecv,tvsend); /*接收和发送的时间差*/
		rtt=tvrecv->tv_sec*1000+tvrecv->tv_usec/1000; /*以毫秒为单位计算rtt*/
		/*显示相关信息*/
		pingsucc = 1;
//		printf("%d byte from %s: icmp_seq=%u ttl=%d rtt=%.3f ms\n", len,inet_ntoa(from->sin_addr),icmp->icmp_seq,ip->ip_ttl,rtt);
	}
	else return -1;
}

unsigned short cal_chksum(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;
}

int set_icmp_head(struct icmp *icmp, int pack_no)
{
	int packsize = 0;
	struct timeval *tval;
	icmp->icmp_type = ICMP_ECHO;
	icmp->icmp_code = 0;
	icmp->icmp_cksum = 0;
	icmp->icmp_seq = pack_no + 1;
	icmp->icmp_id = getpid();
	packsize = 8 + DATALEN;
	tval= (struct timeval *)icmp->icmp_data;
	gettimeofday(tval,NULL);
//	icmp->icmp_data = (char *)malloc(1024);
//	strcpy(icmp->icmp_data, CONTENT);
	icmp->icmp_cksum = cal_chksum((unsigned short *)icmp, packsize);
//		cal_chksum( (unsigned short *)icmp,packsize); /*校验算法*/
	return packsize;
}
//#if 0
int recv_packet(int sockfd)
{
	int i = 0, n = 0, fromlen = 0, ret = 0;
	struct sockaddr_in from;
	struct timeval tvrecv;
	char recvpacket[MAX_SIZE];
	memset(&from, 0, fromlen);
	fromlen = sizeof(from);
//	printf("recv_packet\n");
	 
	if (-1 == fcntl(sockfd, F_SETFL, O_NONBLOCK)){
		printf("fcntl socket error!\n");
		return;
	}
	struct timeval tv;
	fd_set readfds;

	tv.tv_sec = MAX_WAIT_TIME;
	tv.tv_usec = 0;
	FD_ZERO(&readfds);
	FD_SET(sockfd,&readfds);

	for(i = 0; i < SEND_NUM; i++){
//		printf("line:%d, sockfd:%d\n", __LINE__, sockfd);
		if(select(sockfd+1,&readfds,NULL, NULL, &tv) > 0){
//			printf("line:%d, sockfd:%d\n", __LINE__, sockfd);
			if((n = recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr *)&from, &fromlen)) < 0){
				if(errno == EINTR) continue;
				perror("recvfrom error");
				continue;
			}
//			buf_hex_print(recvpacket, n);
			gettimeofday(&tvrecv,NULL); 	/*记录接收时间*/
			if(unpack(recvpacket, n, &tvrecv, &from)==-1) continue;
				ret = 1;
//			break;
		}else{
			ret = 0;
//			 printf("timeout!there is no data arrived!\n");
		}
	}
//	printf("ret:%d\n", ret);
	return ret;
}
//#endif
int send_packet(int sockfd, struct sockaddr_in *dest_addr)
{
	int i = 0, packetsize = 0;
	struct icmp *icmp;
	icmp = (struct icmp *)calloc(1, 1024);
	strcpy((char*)icmp + 8, CONTENT);
	for(i = 0; i < SEND_NUM; i++){
		packetsize = set_icmp_head(icmp, i);
		if(sendto(sockfd, icmp, packetsize, 0, (struct sockaddr *)dest_addr, sizeof(struct sockaddr_in))<0 ){
			perror("sendto error");
			continue;
		}
		usleep(50000);
	}
	free(icmp);
}

int myping(char *strip)
{
	struct hostent *host;
	struct protoent *protocol;
	struct sockaddr_in dest_addr;
	in_addr_t inaddr = 0;
	int waittime = MAX_WAIT_TIME;
	int size = 50*1024;
	int sockfd = 0, ret = 0;
	if( (protocol = getprotobyname("icmp") )==NULL){
		perror("getprotobyname");
		exit(1);
	}
		
	if( (sockfd=socket(AF_INET,SOCK_RAW,protocol->p_proto) )<0){
		perror("socket error");
		exit(1);
	}
	
	setuid(getuid());

//	setsockopt(Sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size) )
		
	bzero(&dest_addr,sizeof(dest_addr));
	dest_addr.sin_family = AF_INET; 
	
	if ((inaddr=inet_addr(strip))==INADDR_NONE){
		if((host=gethostbyname(strip) )==NULL){ /*是主机名*/
			perror("gethostbyname error");
			exit(1);
		}
		memcpy( (char *)&dest_addr.sin_addr,host->h_addr,host->h_length);
	} else {
		dest_addr.sin_addr.s_addr = inaddr;
	}
//	printf("PING %s(%s): %d bytes data in ICMP packets.\n", strip, inet_ntoa(dest_addr.sin_addr), DATALEN);
		
	send_packet(sockfd, &dest_addr);
	
	if(recv_packet(sockfd))
		ret = 1;
//		printf("pingsucc:%d\n", pingsucc);

	return ret;
}

int main(){
	int i = 0, total = 0;
	char str[1024];
#if 1
	for(i = 0; i < 255; i++){
		sprintf(str, "%s%d", "192.168.0.", i);
		if(myping(str)){
			total++;
			printf("ping %s sucess\n", str);
		}else{
			printf("ping %s failed\n", str);
		}

	}
#endif
#if 0
	sprintf(str, "%s%d", "192.168.0.", 100);

	if(myping(str)){
		total++;
		printf("ping %s sucess\n", str);
	}else{
		printf("ping %s failed\n", str);
	}
#endif

	printf("success:%d\n", total);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值