关于ping程序的一点注释.docx
- 文档编号:9524571
- 上传时间:2023-02-05
- 格式:DOCX
- 页数:17
- 大小:24.35KB
关于ping程序的一点注释.docx
《关于ping程序的一点注释.docx》由会员分享,可在线阅读,更多相关《关于ping程序的一点注释.docx(17页珍藏版)》请在冰豆网上搜索。
关于ping程序的一点注释
Ping.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include"busybox.h"
//这里告诉我们linux下的libc5库是不提供icmp支持的,所以如果是libc5库的系统上如果要ping,即需要自己定义相应的icmp结构
/*Itturnsoutthatlibc5doesn'thavepropericmpsupport
*builtintoitheaderfiles,sowehavetosupplementit*/
#if__GNU_LIBRARY__<5
staticconstintICMP_MINLEN=8; //icmp最小也要有8位,用来校验是判断 /*absminimum*/
//以下是定义icmp结构,通常icmp是通过ip包发送的,所以发送的数据在通常是在外先裹层icmp报头,然后在进入网络层裹上ip报头一起发送的,所以接受时,我们往往要跳过ip报头然后把icmp的东西取出来判断 ,这里对ip报头不分析,仅仅定义libc5需要的icmp结构
//常见的icmp通常由typecodecksum组成报头,然后是根据不同需求需要发送的data字段,其中不同需求由type的代码的不同而对data字段的包含也不同,而ping中通常用的是ICMP_ECHO;code是代码段,ping中通常为0;cksum是网络中ip等通常用的校验算法,算法下面解释。
structicmp_ra_addr {
u_int32_tira_addr;
u_int32_tira_preference;
};
structicmp
{
u_int8_t icmp_type; /*typeofmessage,seebelow*/ //这是type
u_int8_t icmp_code; /*typesubcode*/ //这是code
u_int16_ticmp_cksum; /*onescomplementchecksumofstruct*///校验
//注意下面用了union结构,这是因为icmp除了探测主机,即ping外还有其他的功能,根据功能码的不同每次发出去的下面的数据段结构其实是不一样的,在这里我们只需用到structih_idseq 因为这是ping所需要的结构,其他的icmp管理,我们暂时不用管,因为一次只会用到一种数据类型,所以用union定义一个最大的空间
union //发送的各个data的最大值
{
u_charih_pptr; /*ICMP_PARAMPROB*/
structin_addrih_gwaddr; /*gatewayaddress*/
structih_idseq /*echodatagram*///echo是我们关心程序发送给主机用来探测的
{
u_int16_ticd_id; //这个是id
u_int16_ticd_seq; //这个是seq 就是包的顺序
}ih_idseq;
u_int32_tih_void;
/*ICMP_UNREACH_NEEDFRAG--PathMTUDiscovery(RFC1191)*/
structih_pmtu //这个是关于MTU路径的。
不用
{
u_int16_tipm_void;
u_int16_tipm_nextmtu;
}ih_pmtu;
structih_rtradv
{
u_int8_tirt_num_addrs;
u_int8_tirt_wpa;
u_int16_tirt_lifetime;
}ih_rtradv;
}icmp_hun;
#define icmp_pptr icmp_hun.ih_pptr //这个就不多说了,为了使用方便的定义
#define icmp_gwaddr icmp_hun.ih_gwaddr
#define icmp_id icmp_hun.ih_idseq.icd_id
#define icmp_seq icmp_hun.ih_idseq.icd_seq
#define icmp_void icmp_hun.ih_void
#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
union //这里定义必要的主机回复的Union结构,Ping中需要用的是id_ts;代表响应时间
{
struct
{
u_int32_tits_otime;
u_int32_tits_rtime;
u_int32_tits_ttime;
}id_ts;
struct
{
structipidi_ip;
/*optionsandthen64bitsofdata*/
}id_ip;
structicmp_ra_addrid_radv;
u_int32_t id_mask;
u_int8_t id_data[1];
}icmp_dun;
#define icmp_otime icmp_dun.id_ts.its_otime //这个同上
#define icmp_rtime icmp_dun.id_ts.its_rtime
#define icmp_ttime icmp_dun.id_ts.its_ttime
#define icmp_ip icmp_dun.id_ip.idi_ip
#define icmp_radv icmp_dun.id_radv
#define icmp_mask icmp_dun.id_mask
#define icmp_data icmp_dun.id_data
};
#endif
//这里icmp结构定义结束,好象很复杂,但是在ping中真正用到的不多,还有一点,在IP报头中我们还需要用到IP报头长度IHL和生存时间TTL,报头长度用来让我们在ping时如果通过IP路由转发后连IP报头一起返回时跳过到icmp 而ttl是我们ping中需要的,而还需说明的是ip因为是点对点的,不是tcp,所以ping中不需要bind和listen只需把信息发送出去即可;切记
//下面是数据包大小定义,icmp中最小也要有8位,否则就不是icmp因为icmp报头包含type、code和cksum和这三项内容,长度为8位,8位和16位,然后id是16位的,seq是16位的,合起来正好8个字节,这也是icmp的最小长度了。
而最大长度则看下面的定义
//公用基本的数据定义
staticconstintDEFDATALEN=56; //默认报头长度
staticconstintMAXIPLEN=60; //一个最大ip报头长度
staticconstintMAXICMPLEN=76; //一个最大icmp报头长度
staticconstintMAXPACKET=65468; //最大packet,icmp规定最大发送数据data=64k
#define MAX_DUP_CHK (8*128)//这个Ping中没用到,其他地方有用,128个字节
staticconstintMAXWAIT=10; //最大等10秒
staticconstintPINGINTERVAL=1; //两次间隔一秒 /*second*/
#defineO_QUIET (1<<0) //退出
//这段是其他管理用到的,ping程序中没起到什么作用
#define A(bit) rcvd_tbl[(bit)>>3] /*identifybyteinarray*/
#define B(bit) (1<<((bit)&0x07)) /*identifybitinbyte*/
#define SET(bit) (A(bit)|=B(bit))
#define CLR(bit) (A(bit)&=(~B(bit)))
#define TST(bit) (A(bit)&B(bit))
staticvoidping(constchar*host);
/*commonroutines*/
staticintin_cksum(unsignedshort*buf,intsz) //计算校验和的函数
{
intnleft=sz;
intsum=0;
unsignedshort*w=buf;
unsignedshortans=0;
while(nleft>1){
sum+=*w++; //这个意思是把前面的长度以2字节位单位加起来,形成和sum,为什么以2字节为单位呢,因为cksum是个2字节大小的校验和
nleft-=2;
}
if(nleft==1){
*(unsignedchar*)(&ans)=*(unsignedchar*)w;
//如果为奇数时,会多出一个,把它作为两字节数据的高16-8位,它的8-0位添零后在和原sum相加。
这样保证所有长度都加上了
sum+=ans;
}
sum=(sum>>16)+(sum&0xFFFF); //然后是取反求得校验和的过程,这是网络上常用的校验过程
sum+=(sum>>16);
ans=~sum;
return(ans);
}
/*simpleversion*/
#ifndefBB_FEATURE_FANCY_PING //分两种情况,这种没参数
staticchar*hostname=NULL;
staticvoidnoresp(intign) //无返回包输出无值信息
{
printf("Noresponsefrom%s\n",hostname);
exit(0);
}
staticvoidping(constchar*host) //简单版下的ping程序
{
structhostent*h;
structsockaddr_inpingaddr;
structicmp*pkt;
intpingsock,c;
charpacket[DEFDATALEN+MAXIPLEN+MAXICMPLEN]; //申请空间大小,一个ping包一般最大也只能有那么大了
pingsock=create_icmp_socket(); //建立icmp连接
memset(&pingaddr,0,sizeof(structsockaddr_in)); //初始化pingaddr地址大小sockaddr_in的内存空间
pingaddr.sin_family=AF_INET;
h=xgethostbyname(host); //得到主机名
memcpy(&pingaddr.sin_addr,h->h_addr,sizeof(pingaddr.sin_addr));//同理
hostname=h->h_name;
pkt=(structicmp*)packet; //创建icmp包
memset(pkt,0,sizeof(packet));
pkt->icmp_type=ICMP_ECHO; //告之所发送的是探测主机类型的icmp 即ping
pkt->icmp_cksum=in_cksum((unsignedshort*)pkt,sizeof(packet));
//进行校验和计算后添入发送包
c=sendto(pingsock,packet,sizeof(packet),0, //发送给想探测的机器
(structsockaddr*)&pingaddr,sizeof(structsockaddr_in));
if(c<0||c!
=sizeof(packet)) //可能是网络故障,网线不通?
perror_msg_and_die("sendto");
signal(SIGALRM,noresp); //如果超时无响应则退出到noresp,告之机器无响应
alarm(5); //等5秒,简单版就一次ping,要不成功,要不失败 /*givethehost5000mstorespond*/
/*listenforreplies*/
while
(1){
structsockaddr_infrom;
size_tfromlen=sizeof(from);
//接受机器的返回
if((c=recvfrom(pingsock,packet,sizeof(packet),0,
(structsockaddr*)&from,&fromlen))<0){
if(errno==EINTR)
continue;
perror_msg("recvfrom");
continue;
} //icmp的最大长度为76,如果大于,主机返回了ip报头,有这种情况
//如果返回ip报头,首先我们要跳过ip报头,然后才能进行icmp的判断,这就需要ihl长度了
if(c>=76){ /*ip+icmp*/
structiphdr*iphdr=(structiphdr*)packet;
pkt=(structicmp*)(packet+(iphdr->ihl<<2)); /*skipiphdr*/ //跳过ip报头ihl<<2是因为ihl是以4字节为一个单位来记录IP报头的长度,packet+()则跳过长度
if(pkt->icmp_type==ICMP_ECHOREPLY) //如果回复是ping应答类型则成功
break;
}
}
printf("%sisalive!
\n",hostname); //告诉收到主机返回
return;
}
externintping_main(intargc,char**argv) //简单的pingmain甚至不带除主机名之外任何参数
{
argc--;
argv++;
if(argc<1)
show_usage();
ping(*argv); //执行ping
returnEXIT_SUCCESS;
}
//以上是一个简单的ping程序,很简单,只是探测和返回通不通,即没发送什么数据,连时间ttl等都没有显示,它适合比较只需要简单的探测的情况,下面是比较正规的ping
#else/*!
BB_FEATURE_FANCY_PING*/ //带参数的版本,就是较正规的
/*full(er)version*/
staticchar*hostname=NULL; //这些上面都定义了
staticstructsockaddr_inpingaddr;
staticintpingsock=-1;
staticintdatalen;/*intentionallyuninitializedtoworkaroundgccbug*/
staticlongntransmitted=0,nreceived=0,nrepeats=0,pingcount=0; //几个常用数据,用来表示丢失数,收到数,发送数,次数等
staticintmyid=0,options=0;
staticunsignedlongtmin=ULONG_MAX,tmax=0,tsum=0;
staticcharrcvd_tbl[MAX_DUP_CHK/8];
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 关于 ping 程序 一点 注释