从上一篇文章上改变过来,在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);
}