《ping源码程序分析.docx》由会员分享,可在线阅读,更多相关《ping源码程序分析.docx(14页珍藏版)》请在第一文库网上搜索。
1、ping源码分析10.4.1Ping简介Ping是网络中应用非常广泛的一个软件,它是基于ICMP协议的。下面首先对ICMP协议做一简单介绍。ICMP是IP层的一个协议,它是用来探测主机、路由维护、路由选择和流量控制的。ICMP报文的最终报宿不是报宿计算机上的一个用户进程,而是那个计算机上的IP层软件。也就是说,当一个带有错误信息的ICMP报文到达时,IP软件模块就处理本身问题,而不把这个ICMP报文传送给应用程序。ICMP报文类型有:回送(ECHO)回答(0);报宿不可到达(3);报源断开(4);重定向(改变路由)(5);回送(ECHO)请求(8);数据报超时(11);数据报参数问题(12);
2、时间印迹请求(13);时间印迹回答(14);信息请求(15);信息回答(16);地址掩码请求(17);地址掩码回答(18)o虽然每种报文都有不同的格式,但它们开始都有下面三段:一个8位整数报文TYPE(类型)段;一个8位CODE(代码码)段,提供更多的报文类型信息;一个16位CHECKSUM(校验和)段;此外,报告差错的ICMP报文还包含产生问题数据报的网际报头及前64位数据。一个ICMP回送请求与回送回答报文的格式如表10.17所示。表10.17ICMP回送请求与回送回答报文格式类型CODE校验和CHECKSUM标识符序列号嵌入式1inUX应用程序开发详解一第10章、嵌入式1inUX网络编程
3、数据10. 4.2Ping源码分析下面的Ping.c源码是在busybox里实现的源码。在这个完整的Ping.c代码中有较多选项的部分代码,因此,这里先分析除去选项部分代码的函数实现部分流程,接下来再给出完整的Ping代码分析。这样,读者就可以看到一个完整协议实现应该考虑到的各个部分。1 .Ping代码主体流程Ping,c主体流程图如下图10.8所示。另外,由于Ping是IP层的协议,因此在建立SOCket时需要使用SOCK_RAW选项。在循环等待回应信息处,用户可以指定“-f”洪泛选项,这时就会使用SeIeCt函数来指定在一定的时间内进行回应。2 .主要选项说明山调试选项f:洪泛选项i:等待
4、选项r:路由选项1:广播选项Ping函数主要有以下几个选项:(F_SO_DEBUG)(F_F1OOD)(F_INTERVA1)(F_RROUTE)(MU1TICASTNO1OOP)对于这些选项,尤其是路由选项、广播选项和洪泛选项都会有不同的实现代码。另外,ping函数可以接受用户使用的S1GINT和SIGA1ARM信号来结束程序,它们分别指向了不同的结束代码,请读者阅读下面相关代码。图10.8Ping主体流程图3 .源代码及注释(1)主体代码Ping代码的主体部分可以四部分,首先是一些头函数及宏定义:#inc1ude#inc1ude#inc1ude#inc1ude#inc1ude#inc1ud
5、e4inc1ude#inc1ude4inc1ude#inc1ude4inc1udeinc1ude#inc1ude#inc1ude4inc1ude#inc1ude#inc1ude#inc1udedefineF_F100DOxOO1defineF_INTERVA10x0024defineF_NUMERIC0x004defineF_PINGFI11ED0x008defineF_QUIET0x010defineF_RR0UTE0x020#CIefineF_S0_DEBUG0x040#defineF_S0_D0NTR0UTE0x0804defineF_VERB0SE0x100*多播选项*/intmopt
6、ions;4defineMU1TICAST_N0100P0x001#defineMU1TICST.TT10x002defineMu1T1CAST_IF0x004嵌入式1inUX应用程序开发详解一第10章、嵌入式1inUX网络编程接下来的第2部分是建立SOCket并处理选项:Intmain(intargc,char*argv)(structtimeva1timeout;structhostent*hp;structsockaddr_in*to;structprotoent*proto;structin_addrifaddr;inti;intch,fdmask,ho1d,pack1en,pre1o
7、ad;u_char*datap,*packet;char*target,hnamebufMAX1IOSTNAME1EN;u_chartt1,1oop;intam_i_root;staticchar*nu11=NU11;*environ=&nu11;*/am_i_root=(getuid()=0);*建立SoCket连接,并且测试是否是root用户*/if(s=socket(AF_INET,SOCK_RAW,IPPROTO-ICMP)0)if(errno=EPERM)fprintf(stderr,ping:pingmustrunasrootn);)e1seperror(,ping:socket1
8、);exit(2);)pre1oad=0;datap=Goutpack8+sizeof(structtimeva1);whi1e(ch=getopt(argc,argv,I:1Rc:dfh:i:1:np:qrs:t:vn)!=EOF)switch(ch)case,c,:npackets=atoi(optarg);if(npackets=0)(void)fprintf(stderr,r,ping:badnumberofpacketstotransmit,nr,);exit(2);)break;*调用选项*/case,d,:optionsI=F_SO_DEBUG;break;*fIood选项*/c
9、ase,f,:if(!am_i_root)(void)fprintf(stderr,ping:%snn,strerror(EPERM);exit(2);)optionsI=F_F1OOD;setbuf(stdout,NU11);break;*等待选项*/case,i,:*waitbetweensendingpackets*/interva1=atoi(optarg);if(interva1=0)(void)fprintf(stderr,ping:badtiminginterva1,n,);exit;)options=F_INTERVA1;break;case,1,:if(!am_i_root)
10、(void)fprintf(stderr,ping:%snr,strerror(EPERM);exit;)pre1oad=atoi(optarg);if(pre1oadsin_fami1y=AF_INET;*地址点换函数*/if(inet_aton(target,&to-sin_addr)hostname=target;)e1se#if0char*adc1r=reso1ve_name(target,0);if(!addr)(void)fprintf(stderr,ping:unknownhost%snr,target);exit(2);)to-sin-addr.s_addr=inet_addr
11、(addr);hostname=target;fte1se*调用gethostbyname识别主机名*/hp=gethostbyname(target);if(Ihp)(void)fprintf(stderr,ping:unknownhost%sn,target);exit(2);)to-sin-fami1y=hp-h_addrtype;if(hp-h_1ength(int)sizeof(to-sin_addr)hp-h-1ength=sizeof(to-sin-addr);)memcpy(&to-sin_addr,hp-h-addr,hp-h-1ength);(void)strncpy(hn
12、amebuf,hp-h_name,sizeof(hnamebuf)-1);hostname=hnamebuf;#endif)接下来的一部分主要是对各个选项(如路由、多播)的处理,这里就不做介绍了。再接下来是Ping函数的最主要部分,就是接收无限循环回应信息,这里主要用到T函数recvfroio另外,对用户中断信息也有相应的处理,如下所示:if(to-sin_famiIy=AF_INET)(void)printf(r,PTNG%s(%s):%ddatabytesnr,hostname,inet_ntoa(*(structin_addr*)&to-sin_addr.s_addr),data1en)
13、;e1se(void)printf(,PING%s:%ddatabytesn,hostname,data1en);*若程序接收到S1GINT或SIGA1RM信号,调用相关的函数*/(void)signa1(SIGINT,finish);(void)signa1(SIGA1RM,catcher);*循环等待客户端的回应信息*/for(;)structsockaddr_infrom;registerintcc;intfrom1en;if(options&F_F1OOD)*形成ICMP回应薪据包,在后面会有讲解*/pinger();/*设定等待实践*/timeout.tv_sec=0;timeout.tv_usec=10000;fdmask=1s;*调用SeIeCt函数*/嵌入式1inUX应用程序开发详解一第10章、嵌入式1inUX网络编程if(se1ect(s+1,(fd_set*)&fdmask,(fd_set*)NU11,(fd