关键词不能为空

当前您在: 主页 > 英语 >

ping的详细解释

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-03-03 12:40
tags:

-

2021年3月3日发(作者:植树)


Ping.c


#include


#include


#include


#include


#include


#include



#include


#include


#include


#include


#include


#include


#include


#include


#include


#include


#include


#include







//


这里告诉我们

< p>
linux


下的


libc5


库是不提供


icmp


支持的,



所以如果是


libc5


库的


系统上如果要


ping ,


即需要自己定义相应的


icmp


结构



/* It turns out that libc5 doesn't have proper icmp support


* built into it header files, so we have to supplement it */


#if __GNU_LIBRARY__ < 5

















static


const


int


ICMP_MINLEN


=


8;





//icmp


最小也要有


8


位,用来校验是判















/* abs minimum */












//

< br>以下是定义


icmp


结构,通常


icmp


是通过


ip


包发送的,所以发 送的数据在



通常是


在外先裹层


icmp


报头,然后在进入网络层裹上


ip< /p>


报头一起发送的,所以接受时,我们往往


要跳过

< br>ip


报头



然后把


icmp


的东西取出来判断



,这里对


ip


报头不分析,仅仅定义


libc5


需要的


icmp


结构






//


常见的


icmp


通常由


type


code


cksum


组成报头,


< p>
然后是根据不同需求需要发送的


data


字段,其 中不同需求




type


的代码的不同



而对


dat a


字段的包含也不同,而


ping


中通


常用的是


ICMP_ECHO


;co de


是代码段,


ping


中通常为


0


;cksum


是网络中


ip


等通常用的校


验算法,算法下面解释。



struct icmp_ra_addr











{


u_int32_t ira_addr;


u_int32_t ira_preference;


};



struct icmp


{


u_int8_t icmp_type;





/* type of message, see below */










//


这是


type


u_int8_t icmp_code;





/* type sub code */
















//


这是


code


u_int16_t icmp_cksum;





/* ones complement checksum of struct */ //


校验




//


注意下面用了


union


结构,这 是因为


icmp


除了探测主机,即


pi ng


外还有其他的功能,根


据功能码的不同每次发出去的下面的 数据段结构其实是不一样的,在这里我们只需用到


struct ih_idseq



因为这是


ping


所需要的结构,其他的


icmp


管理, 我们暂时不用管,因为一


次只会用到一种数据类型


,

< p>
所以用


union


定义一个最大的空间

< p>


union























//


发 送的各个


data


的最大值



{




u_char ih_pptr;









/* ICMP_PARAMPROB */






struct in_addr ih_gwaddr;





/* gateway address */




struct ih_idseq









/* echo datagram */ //echo


是我 们关心程序发送给主机用来探


测的





{




u_int16_t icd_id;



















//


这个是


id




u_int16_t icd_seq;

















//


这个是


seq



就是包的顺序





} ih_idseq;




u_int32_t ih_void;





/* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */




struct ih_pmtu



















//< /p>


这个是关于


MTU


路径的。不用





{




u_int16_t ipm_void;




u_int16_t ipm_nextmtu;




} ih_pmtu;





struct ih_rtradv

































{




u_int8_t irt_num_addrs;




u_int8_t irt_wpa;




u_int16_t irt_lifetime;




} ih_rtradv;


} icmp_hun;


#define





icmp_pptr





icmp__pptr









//


这个就不多说了,


为了使用


方便的定义















#define





icmp_gwaddr





icmp__gwaddr


#define





icmp_id









icmp___id


#define





icmp_seq





icmp___seq


#define





icmp_void





icmp__void


#define





icmp_pmvoid





icmp___void


#define





icmp_nextmtu





icmp___nextmtu


#define





icmp_num_addrs





icmp___num_addrs


#define





icmp_wpa





icmp___wpa


#define





icmp_lifetime





icmp___lifetime


union












//< /p>


这里定义必要的主机回复的


Union


结 构,


Ping


中需要用的是


id_ts ;


代表响应时间



{




struct




{




u_int32_t its_otime;




u_int32_t its_rtime;




u_int32_t its_ttime;




} id_ts;




struct




{




struct ip idi_ip;




/* options and then 64 bits of data */




} id_ip;




struct icmp_ra_addr id_radv;




u_int32_t


id_mask;




u_int8_t



id_data[1];


} icmp_dun;




#define





icmp_otime





icmp___otime






//


这个同上



#define





icmp_rtime





icmp___rtime


#define





icmp_ttime





icmp___ttime


#define





icmp_ip









icmp___ip


#define





icmp_radv





icmp__radv


#define





icmp_mask





icmp__mask


#define





icmp_data





icmp__data


};


#endif





















//


这里


icmp


结构定义结束,好象很复杂,但是在

< br>ping


中真正用到的不多,还有一点,在


IP


报头中我们还需要用到


IP


报头长度

< p>
IHL


和生存时间


TTL



报头长度用来让我们在


ping


时如


果通过


IP


路由转发后连


IP


报头一起返回时跳过到


icmp

< p>


ttl


是我们


ping


中需要的,而还


需说明的是


ip


因为是点对点的,不是


tcp,


所以


ping


中不需要


bind


listen


只需把信息发送


出去即可


;


切记




//


下面是数据包大小定义




icmp


中最小也要有


8


位,否则就不是


icmp


因为< /p>


icmp


报头包含


type



code



cksum< /p>


和这三项内容,长度为


8


位,

< p>
8


位和


16


< p>
,


然后


id


< p>
16


位的,


seq



16


位的,合起来正好


8

< br>个字节,这也是


icmp


的最小长度了。而最大长度则看 下面的定义



//


公用基本的数据定义



static const int DEFDATALEN = 56;







//


默认报头长度












static const int MAXIPLEN = 60;








//


一个 最大


ip


报头长度



static const int MAXICMPLEN = 76;







//


一个最大


icmp


报头长度




static const int MAXPACKET = 65468;




< br>//


最大


packet



icmp


规定最大发送数据


data=64k






#define





MAX_DUP_CHK





(8 * 128) //< /p>


这个


Ping


中没用到,其他地方有用< /p>




128


个字 节



static const int MAXWAIT = 10;






//


最大等


10




static const int PINGINTERV


AL = 1;






//


两次间隔一秒












/* second */



#define O_QUIET




(1 << 0)






//


退出




//


这段是其他管理用到的,


pin g


程序中没起到什么作用



#define





A(bit)









rcvd_tbl[(bit)>>3]





/* identify byte in array */


#define





B(bit)









(1 << ((bit) & 0x07))





/* identify bit in byte */


#define





SET(bit)





(A(bit) |= B(bit))


#define





CLR(bit)





(A(bit) &= (~B(bit)))


#define





TST(bit)





(A(bit) & B(bit))



static void ping(const char *host);



/* common routines */


static int in_cksum(unsigned short *buf, int sz)








//


计算校验和的函数



{






int nleft = sz;






int sum = 0;






unsigned short *w = buf;






unsigned short ans = 0;







while (nleft > 1) {










sum += *w++;




//


这个意思是把前面的长度以


2


字节位单位加起来,


形成



sum,


为什么以


2


字 节为单位呢,因为


cksum


是个


2< /p>


字节大小的校验和











nleft -= 2;






}







if (nleft == 1) {










*(unsigned char *) (&ans) = *(unsigned char *) w;























//


如果为奇数时,会多出一个,



把它作为


两字节数据的高


16-8


位,它的


8-0


位添零后在和原

< p>
sum


相加。这样保证所有长度都加上了











sum += ans;






}







sum = (sum >> 16) + (sum & 0xFFFF);


//


然后是取反求得校验和的过程,这是网络上


常用的校验过程







sum += (sum >> 16);






ans = ~sum;






return (ans);


}



/* simple version */


#ifndef BB_FEATURE_FANCY_PING





//


分两种情况



,这种没参数



static char *hostname = NULL;



static


void


noresp(int


ign)





















//


无返 回包输出无值信




{






printf(






exit(0);


}



static void ping(const char *host)













//


简单版下的

ping


程序



{






struct hostent *h;






struct sockaddr_in pingaddr;






struct icmp *pkt;






int pingsock, c;






char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];



//


申请 空间大小,一个


ping


包一般最大也只能有那么大了








pingsock = create_icmp_socket();














//


建立


icmp


连接







memset(&pingaddr,


0,


sizeof(struct


sockaddr_in)); //





p ingaddr






sockaddr_in


的内存空间








_family = AF_INET;




















h = xgethostbyname(host);

















//


得到主机名







memcpy(&_addr, h->h_addr, sizeof(_addr)); //


同理







hostname = h->h_name;
















pkt = (struct icmp *) packet;







//

< br>创建


icmp








memset(pkt, 0, sizeof(packet));






pkt->icmp_type = ICMP_ECHO;




//


告之所发送的是探测主机类型的


icmp




ping






pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));
































//


进行校验和计算后添


入发送包







c = sendto(pingsock, packet, sizeof(packet), 0,



//


发送给想探测的机器
















(struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in));







if (c < 0 || c != sizeof(packet))










//


可能是网络故障,网线不通?











perror_msg_and_die(







signal(SIGALRM,


noresp);






//


如果超时无响应则退出到


noresp,


告之机器无响








alarm(5);






//


等5秒

< br>,


简单版就一次


ping



要不成功,


要不失败










/*


give the host 5000ms to respond */






/* listen for replies */






while (1) {





























struct sockaddr_in from;




















size_t fromlen = sizeof(from);




























//


接受机器的返回











if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,


























(struct sockaddr *) &from, &fromlen)) < 0) {














if (errno == EINTR)


















continue;














perror_msg(














continue;











}



//icmp


的最大长度为76


,


如果 大于,主机返回了


ip


报头,有这种情况



//


如果返回


ip


报头,首先我们要跳过


ip


报头,然后才能进行


icmp


的判断,这就需要


ihl



度了











if (c >= 76) {













/* ip + icmp */














struct iphdr *iphdr = (struct iphdr *) packet;















pkt


=


(struct


icmp


*)


(packet


+


(iphdr->ihl


<<


2));





/*


skip


ip


hdr


*/










//


跳过


ip


报头


< p>
ihl<<2


是因为


ihl


是以


4


字节为一个单位来记录


IP< /p>



头的长度




packet+()


则跳过长度
















if (pkt->icmp_type == ICMP_ECHOREPL


Y) //


如果回复是


ping


应答类型


则成功



















break;










}






}






printf(








//


告诉收到主机返回







return;


}



extern int ping_main(int argc, char **argv)





//


简单的


ping main


甚至不带除主机名之外任


何参数



{






argc--;






argv++;






if (argc < 1)










show_usage();






ping(*argv);















//


执行


ping






return EXIT_SUCCESS;


}



//


以上是一个简单的


ping


程序,很简单,只是探测和返回通不通,即没发送什么数据,连时< /p>

-


-


-


-


-


-


-


-



本文更新与2021-03-03 12:40,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/699972.html

ping的详细解释的相关文章