ping命令的作用是通过icmp协议来发送数据包,若ICMP报头为奇数个字节,会剩下最后一字节。把最后一个字节视为一个2字节数据的高
if( nleft==1)
{ *(unsigned char *)(&answer)=*(unsigned char *)w;
sum+=answer;
}
sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
answer=~sum;
return answer;
}
"回响请求消息来验证与另一台TCP/IP计算机的IP级连接状态,
进行相关的进程调度。
获取main的进程id,用于设置ICMP的标志符 pid=getpid();
printf("PING %s(%s): %d bytes data in ICMP packets.\n",argv[1],
inet_ntoa(dest_addr.sin_addr),datalen);
send_packet(); /*发送所有ICMP报文*/
recv_packet(); /*接收所有ICMP报文*/
statistics(SIGALRM); /*进行统计*/
return 0;
}
回响应答消息的接收情况将和往返过程的次数一起显示出来.
ping命令是用于检测网络连接性 可到达性和名称解析的疑难问题的主要TCP/IP命令.
1.基于icmp的接口函数命令,发送数据使用sendto()函数,接收数据使用recvfrom()函数。
2.把ICMP报头二进制数据以2字节为单位累加起来
while(nleft>1)
{ sum+=*w++;
nleft-=2;
}
3.设置ICMP报
int pack(int pack_no)
{ int i,packsize;
struct icmp *icmp;
struct timeval *tval;
icmp=(struct icmp*)sendpacket;
icmp->icmp_type=ICMP_ECHO;
icmp->icmp_code=0;
icmp->icmp_cksum=0;
icmp->icmp_seq=pack_no;
icmp->icmp_id=pid;
packsize=8+datalen;
tval= (struct timeval *)icmp->icmp_data;
gettimeofday(tval,NULL);
icmp->icmp_cksum=cal_chksum( (unsigned short *)icmp,packsize);
return packsize;
}
sendpacket为要发送的内容,由pack()函数设定,dest_addr是目的地址,
4.接收所有ICMP报文
void recv_packet()
{ int n,fromlen;
extern int errno;
signal(SIGALRM,statistics);
fromlen=sizeof(from);
while( nreceived<nsend)
{
//alarm()用来设置信号SIGALRM在经过参数seconds指定的秒数后传送给目前的进程
alarm(MAX_WAIT_TIME);
if( (n=recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,
(struct sockaddr *)&from,&fromlen)) <0)
{ if(errno==EINTR) continue;
perror("recvfrom error");
continue;
}
gettimeofday(&tvrecv,NULL);
if(unpack(recvpacket,n)==-1)continue;
nreceived++;
}
}
5.求ip报头长度,即ip报头的长度标志乘4,头长度指明头中包含的4字节字的个数。可接受的最小值是5,最大值是15
iphdrlen=ip->ip_hl<<2;
icmp=(struct icmp *)(buf+iphdrlen);
len-=iphdrlen;
if( len<8) /*小于ICMP报头长度则不合理*/
{ printf("ICMP packets\'s length is less than 8\n");
return -1;
}
6.判断是主机名还是ip地址
if( inaddr=inet_addr(argv[1])==INADDR_NONE)
{ if((host=gethostbyname(argv[1]) )==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 = inet_addr(argv[1]);