实验3icmp协议实践ping解析.docx
《实验3icmp协议实践ping解析.docx》由会员分享,可在线阅读,更多相关《实验3icmp协议实践ping解析.docx(11页珍藏版)》请在冰豆网上搜索。
实验3icmp协议实践ping解析
计算机网络实验上机指导书
专业
班级
学号
姓名
沈阳工程学院信息工程系
实验2ICMP协议实践--ping解析
一.实验目的
掌握ICMP原理,利用其实现网络主机状态测试。
二.实验内容
利用ICMP协议原理编程实现PING命令,测试目标主机是否可到达。
并了解Ping实现原理。
三.实验前的准备
了解ICMP原理及相关概念。
掌握相关软件编程知识。
四.实验要求及实验软硬件环境
【基本要求】
设计程序完成PING命令。
完成此项实验,完成实验报告。
【实验组织方式】
个人实验
【实验条件】
局域网环境下微机两台,编程软件。
五.实验步骤
六..了解ICMP原理以及网络编程
(1)源程序:
Windows
PingPingPingPingPingPingS.ArmyBallisticResearchLaboratory
*/
while(nleft>1){
sum+=*w++;
nleft-=2;
}
/*mopupanoddbyte,ifnecessary*/
if(nleft==1){
u_shortu=0;
*(u_char*)(&u)=*(u_char*)w;
sum+=u;
}
/*
*addbackcarryoutsfromtop16bitstolow16bits
*/
sum=(sum>>16)+(sum&0xffff);/*addhi16tolow16*/
sum+=(sum>>16);/*addcarry*/
answer=~sum;/*truncateto16bits*/
return(answer);
}
实验结果如图6-1所示。
图6-1ping程序运行结果
(2)LINUX
/*简单的ping程序*/
#include<>
#include<>
#include
#include
#include
#include<>
#include
#include
#include
#include<>
#include<>
#include<>
#definePACKET_SIZE4096
#defineMAX_WAIT_TIME5
#defineMAX_NO_PACKETS3
charsendpacket[PACKET_SIZE];
charrecvpacket[PACKET_SIZE];
intsockfd,datalen=56;
intnsend=0,nreceived=0;
structsockaddr_indest_addr;
pid_tpid;
structsockaddr_infrom;
structtimevaltvrecv;
voidstatistics(intsigno);
unsignedshortcal_chksum(unsignedshort*addr,intlen);
intpack(intpack_no);
voidsend_packet(void);
voidrecv_packet(void);
intunpack(char*buf,intlen);
voidtv_sub(structtimeval*out,structtimeval*in);
voidstatistics(intsigno)
{printf("\n--------------------PINGstatistics-------------------\n");
printf("%dpacketstransmitted,%dreceived,%%%dlost\n",nsend,nreceived,
(nsend-nreceived)/nsend*100);
close(sockfd);
exit
(1);
}
/*校验和算法*/
unsignedshortcal_chksum(unsignedshort*addr,intlen)
{intnleft=len;
intsum=0;
unsignedshort*w=addr;
unsignedshortanswer=0;
/*把ICMP报头二进制数据以2字节为单位累加起来*/
while(nleft>1)
{sum+=*w++;
nleft-=2;
}
/*若ICMP报头为奇数个字节,会剩下最后一字节。
把最后一个字节视为一个2字节数据的高字节,这个2字节数据的低字节为0,继续累加*/
if(nleft==1)
{*(unsignedchar*)(&answer)=*(unsignedchar*)w;
sum+=answer;
}
sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
answer=~sum;
returnanswer;
}
/*设置ICMP报头*/
intpack(intpack_no)
{inti,packsize;
structicmp*icmp;
structtimeval*tval;
icmp=(structicmp*)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=(structtimeval*)icmp->icmp_data;
gettimeofday(tval,NULL);/*记录发送时间*/
icmp->icmp_cksum=cal_chksum((unsignedshort*)icmp,packsize);/*校验算法*/
returnpacksize;
}
/*发送三个ICMP报文*/
voidsend_packet()
{intpacketsize;
while(nsend{nsend++;
packetsize=pack(nsend);/*设置ICMP报头*/
if(sendto(sockfd,sendpacket,packetsize,0,
(structsockaddr*)&dest_addr,sizeof(dest_addr))<0)
{perror("sendtoerror");
continue;
}
sleep
(1);/*每隔一秒发送一个ICMP报文*/
}
}
/*接收所有ICMP报文*/
voidrecv_packet()
{intn,fromlen;
externinterrno;
signal(SIGALRM,statistics);
fromlen=sizeof(from);
while(nreceived{alarm(MAX_WAIT_TIME);
if((n=recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,
(structsockaddr*)&from,&fromlen))<0)
{if(errno==EINTR)continue;
perror("recvfromerror");
continue;
}
gettimeofday(&tvrecv,NULL);/*记录接收时间*/
if(unpack(recvpacket,n)==-1)continue;
nreceived++;
}
}
/*剥去ICMP报头*/
intunpack(char*buf,intlen)
{inti,iphdrlen;
structip*ip;
structicmp*icmp;
structtimeval*tvsend;
doublertt;
ip=(structip*)buf;
iphdrlen=ip->ip_hl<<2;/*求ip报头长度,即ip报头的长度标志乘4*/
icmp=(structicmp*)(buf+iphdrlen);/*越过ip报头,指向ICMP报头*/
len-=iphdrlen;/*ICMP报头及ICMP数据报的总长度*/
if(len<8)/*小于ICMP报头长度则不合理*/
{printf("ICMPpackets\'slengthislessthan8\n");
return-1;
}
/*确保所接收的是我所发的的ICMP的回应*/
if((icmp->icmp_type==ICMP_ECHOREPLY)&&(icmp->icmp_id==pid))
{tvsend=(structtimeval*)icmp->icmp_data;
tv_sub(&tvrecv,tvsend);/*接收和发送的时间差*/
rtt=*1000+1000;/*以毫秒为单位计算rtt*/
/*显示相关信息*/
printf("%dbytefrom%s:
icmp_seq=%uttl=%drtt=%.3fms\n",
len,
inet_ntoa,
icmp->icmp_seq,
ip->ip_ttl,
rtt);
}
elsereturn-1;
}
main(intargc,char*argv[])
{structhostent*host;
structprotoent*protocol;
unsignedlonginaddr=0l;
intwaittime=MAX_WAIT_TIME;
intsize=50*1024;
if(argc<2)
{printf("usage:
%shostname/IPaddress\n",argv[0]);
exit
(1);
}
if((protocol=getprotobyname("icmp"))==NULL)
{perror("getprotobyname");
exit
(1);
}
/*生成使用ICMP的原始套接字,这种套接字只有root才能生成*/
if((sockfd=socket(AF_INET,SOCK_RAW,protocol->p_proto))<0)
{perror("socketerror");
exit
(1);
}
/*回收root权限,设置当前用户权限*/
setuid(getuid());
/*扩大套接字接收缓冲区到50K这样做主要为了减小接收缓冲区溢出的
的可能性,若无意中ping一个广播地址或多播地址,将会引来大量应答*/
setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size));
bzero(&dest_addr,sizeof(dest_addr));
=AF_INET;
/*判断是主机名还是ip地址*/
if(inaddr=inet_addr(argv[1])==INADDR_NONE)
{if((host=gethostbyname(argv[1]))==NULL)/*是主机名*/
{perror("gethostbynameerror");
exit
(1);
}
memcpy((char*)&,host->h_addr,host->h_length);
}
else/*是ip地址*/
memcpy((char*)&dest_addr,(char*)&inaddr,host->h_length);
/*获取main的进程id,用于设置ICMP的标志符*/
pid=getpid();
printf("PING%s(%s):
%dbytesdatainICMPpackets.\n",argv[1],
inet_ntoa,datalen);
send_packet();/*发送所有ICMP报文*/
recv_packet();/*接收所有ICMP报文*/
statistics(SIGALRM);/*进行统计*/
return0;
}
/*两个timeval结构相减*/
voidtv_sub(structtimeval*out,structtimeval*in)
{if((out->tv_usec-=in->tv_usec)<0)
{--out->tv_sec;
out->tv_usec+=1000000;
}
out->tv_sec-=in->tv_sec;
}
/*-------------TheEnd-----------*/
运行结果如图6-2所示。
图6-2linux下运行ping程序
作业题:
1.阅读Ping程序
2.理解程序原理