从Ping 127.0.0.1开始
Ping是潜水艇人员的专用术语,表示回应的声纳脉冲,在网络中Ping 是一个十分好用的TCP/IP工具。它主要的功能是用来检测网络的连通情况和分析网络速度。
先给出一段部分ping的代码基本实现:
/****统计数据函数****/
void statistics(int sig)
{
computer_rtt(); //计算rtt
printf("\n------ %s ping statistics ------\n",addr[0]);
printf("%d packets transmitted,%d received,%d%% packet loss,time %.f ms\n",
nsend,nreceived,(nsend-nreceived)/nsend*100,all_time);
printf("rtt min/avg/max/mdev = %.3f/%.3f/%.3f/%.3f ms\n",
min,avg,max,mdev);
close(sockfd);
exit(1);
}
/****检验和算法****/
unsigned short cal_chksum(unsigned short *addr,int len)
{
int nleft = len;
int sum = 0;
unsigned short *w = addr;
unsigned short check_sum = 0;
while(nleft>1) //ICMP包头以字(2字节)为单位累加
{
sum += *w++;
nleft -= 2;
}
if(nleft == 1) //ICMP为奇数字节时,转换最后一个字节,继续累加
{
*(unsigned char *)(&check_sum) = *(unsigned char *)w;
sum += check_sum;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
check_sum = ~sum; //取反得到校验和
return check_sum;
}
/*设置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_ECHO类型的类型号为0
icmp->icmp_code = 0;
icmp->icmp_cksum = 0;
icmp->icmp_seq = pack_no; //发送的数据报编号
icmp->icmp_id = pid;
packsize = 8 + datalen; //数据报大小为64字节
tval = (struct timeval *)icmp->icmp_data;
gettimeofday(tval,NULL); //记录发送时间
//校验算法
icmp->icmp_cksum = cal_chksum((unsigned short *)icmp,packsize);
return packsize;
}
/****发送三个ICMP报文****/
void send_packet()
{
int packetsize;
if(nsend < MAX_NO_PACKETS)
{
nsend++;
packetsize = pack(nsend); //设置ICMP报头
//发送数据报
if(sendto(sockfd,sendpacket,packetsize,0,
(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0)
{
perror("sendto error");
}
}
}
/****接受所有ICMP报文****/
void recv_packet()
{
int n,fromlen;
extern int error;
fromlen = sizeof(from);
if(nreceived < nsend)
{
//接收数据报
if((n = recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,
(struct sockaddr *)&from,&fromlen)) < 0)
{
perror("recvfrom error");
}
gettimeofday(&tvrecv,NULL); //记录接收时间
unpack(recvpacket,n); //剥去ICMP报头
nreceived++;
}
}
/******剥去ICMP报头******/
int unpack(char *buf,int len)
{
int i;
int iphdrlen; //ip头长度
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报头及数据报的总长度
if(