关于ping程序的一点注释.docx

上传人:b****7 文档编号:9524571 上传时间:2023-02-05 格式:DOCX 页数:17 大小:24.35KB
下载 相关 举报
关于ping程序的一点注释.docx_第1页
第1页 / 共17页
关于ping程序的一点注释.docx_第2页
第2页 / 共17页
关于ping程序的一点注释.docx_第3页
第3页 / 共17页
关于ping程序的一点注释.docx_第4页
第4页 / 共17页
关于ping程序的一点注释.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

关于ping程序的一点注释.docx

《关于ping程序的一点注释.docx》由会员分享,可在线阅读,更多相关《关于ping程序的一点注释.docx(17页珍藏版)》请在冰豆网上搜索。

关于ping程序的一点注释.docx

关于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模板 > 简洁抽象

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1