微软ping程序源代码完整版

微软ping程序源代码完整版
编写自己的一个ping程序,可以说是许多人迈出网络编程的第一步吧!!这个ping程序的源代码经过我的修改和调试,基本上可以取代windows中自带的ping程序. 各个模块后都有我的详细注释和修改日志,希望能够对大家的学习
  1  /*   本程序的主要源代码来自MSDN网站, 笔者只是做了一些改进和注释! 另外需要注意的是在Build之前,必须加入ws2_32.lib库文件,
否则会提示"error LNK2001:"的错误!
*/
  2 
  3  /* *****************************************************************************\ 
  4  | Version 1.1 修改记录:                                                        | 
  5  |    <1> 解决了socket阻塞的问题,从而能够正确地处理超时的请求!                  | 
  6  |------------------------------------------------------------------------------| 
  7  | Version 1.2 修改记录:                                                        | 
  8  |    <1> 增加了由用户控制发送ICMP包的数目的功能(即命令的第二个参数).           |    
  9  |    <2> 增加了对ping结果的统计功能.                                           | 
 10  \***************************************************************************** */  
 11 
 12  #pragma pack( 4
 13 
 14  #include  < WINSOCK2.H >      
 15  #include  < STDIO.H >      
 16  #include  < STDLIB.H >  
 17 
 18  #define  ICMP_ECHO 8 
 19  #define  ICMP_ECHOREPLY 0 
 20 
 21  #define  ICMP_MIN 8  //  minimum 8 byte icmp packet (just header) 
 22 
 23  /*  The IP header  */  
 24  typedef  struct  iphdr { 
 25      unsigned  int  h_len: 4 //  length of the header 
 26      unsigned  int  version: 4 //  Version of IP 
 27      unsigned  char  tos;  //  Type of service 
 28      unsigned  short  total_len;  //  total length of the packet 
 29      unsigned  short  ident;  //  unique identifier 
 30      unsigned  short  frag_and_flags;  //  flags 
 31      unsigned  char  ttl; 
 32      unsigned  char  proto;  //  protocol (TCP, UDP etc) 
 33      unsigned  short  checksum;  //  IP checksum 
 34 
 35      unsigned  int  sourceIP; 
 36      unsigned  int  destIP; 
 37 
 38  }IpHeader; 
 39 
 40  //  
 41  //  ICMP header 
 42  //  
 43  typedef  struct  icmphdr { 
 44      BYTE i_type; 
 45      BYTE i_code;  /*  type sub code  */  
 46      USHORT i_cksum; 
 47      USHORT i_id; 
 48      USHORT i_seq; 
 49       /*  This is not the std header, but we reserve space for time  */  
 50      ULONG timestamp; 
 51  }IcmpHeader; 
 52 
 53  #define  STATUS_FAILED 0xFFFF 
 54  #define  DEF_PACKET_SIZE    32 
 55  #define  DEF_PACKET_NUMBER  4    /* 发送数据报的个数 */ 
 56  #define  MAX_PACKET 1024 
 57 
 58  #define  xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s)) 
 59  #define  xfree(p) HeapFree (GetProcessHeap(),0,(p)) 
 60 
 61  void  fill_icmp_data( char   * int ); 
 62  USHORT checksum(USHORT  * int ); 
 63  int  decode_resp( char   * , int  , struct  sockaddr_in  * ); 
 64 
 65  void  Usage( char   * progname){ 
 66 
 67      fprintf(stderr, " Usage:\n " ); 
 68      fprintf(stderr, " %s [number of packets] [data_size]\n " ,progname); 
 69      fprintf(stderr, " datasize can be up to 1Kb\n " ); 
 70      ExitProcess(STATUS_FAILED); 
 71 
 72 
 73  int  main( int  argc,  char   ** argv){ 
 74 
 75      WSADATA wsaData; 
 76      SOCKET sockRaw; 
 77       struct  sockaddr_in dest,from; 
 78       struct  hostent  *  hp; 
 79       int  bread,datasize,times; 
 80       int  fromlen  =   sizeof (from); 
 81       int  timeout  =   1000
 82       int  statistic  =   0 ;   /*  用于统计结果  */   
 83       char   * dest_ip; 
 84       char   * icmp_data; 
 85       char   * recvbuf; 
 86      unsigned  int  addr = 0
 87      USHORT seq_no  =   0
 88 
 89       if  (WSAStartup(MAKEWORD( 2 , 1 ), & wsaData)  !=   0 ){ 
 90          fprintf(stderr, " WSAStartup failed: %d\n " ,GetLastError()); 
 91          ExitProcess(STATUS_FAILED); 
 92      } 
 93 
 94       if  (argc  < 2  ) { 
 95          Usage(argv[ 0 ]); 
 96      } 
 97      sockRaw  =  WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,  0 ,WSA_FLAG_OVERLAPPED); 
 98 
 99       //  
100       // 注:为了使用发送接收超时设置(即设置SO_RCVTIMEO, SO_SNDTIMEO), 
101       //     必须将标志位设为WSA_FLAG_OVERLAPPED ! 
102       //  
103 
104       if  (sockRaw  ==  INVALID_SOCKET) { 
105          fprintf(stderr, " WSASocket() failed: %d\n " ,WSAGetLastError()); 
106          ExitProcess(STATUS_FAILED); 
107      } 
108      bread  =  setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,( char * ) & timeout, 
109           sizeof (timeout)); 
110       if (bread  ==  SOCKET_ERROR) { 
111          fprintf(stderr, " failed to set recv timeout: %d\n " ,WSAGetLastError()); 
112          ExitProcess(STATUS_FAILED); 
113      } 
114      timeout  =   1000
115      bread  =  setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,( char * ) & timeout, 
116           sizeof (timeout)); 
117       if (bread  ==  SOCKET_ERROR) { 
118          fprintf(stderr, " failed to set send timeout: %d\n " ,WSAGetLastError()); 
119          ExitProcess(STATUS_FAILED); 
120      } 
121      memset( & dest, 0 , sizeof (dest)); 
122 
123      hp  =  gethostbyname(argv[ 1 ]); 
124 
125       if  ( ! hp){ 
126          addr  =  inet_addr(argv[ 1 ]); 
127      } 
128       if  (( ! hp)  &&  (addr  ==  INADDR_NONE) ) { 
129          fprintf(stderr, " Unable to resolve %s\n " ,argv[ 1 ]); 
130          ExitProcess(STATUS_FAILED); 
131      } 
132 
133       if  (hp  !=  NULL) 
134          memcpy( & (dest.sin_addr),hp -> h_addr,hp -> h_length); 
135       else  
136          dest.sin_addr.s_addr  =  addr; 
137 
138       if  (hp) 
139          dest.sin_family  =  hp -> h_addrtype; 
140       else  
141          dest.sin_family  =  AF_INET; 
142 
143      dest_ip  =  inet_ntoa(dest.sin_addr); 
144 
145       //  
146       //   atoi函数原型是: int atoi( const char *string ); 
147       //   The return value is 0 if the input cannot be converted to an integer ! 
148       //  
149       if (argc > 2
150      { 
151          times = atoi(argv[ 2 ]); 
152           if (times  ==   0
153              times = DEF_PACKET_NUMBER; 
154      } 
155       else  
156          times = DEF_PACKET_NUMBER; 
157 
158       if  (argc  > 3
159      { 
160          datasize  =  atoi(argv[ 3 ]); 
161           if  (datasize  ==   0
162              datasize  =  DEF_PACKET_SIZE; 
163           if  (datasize  > 1024 )    /*  用户给出的数据包大小太大  */  
164          { 
165              fprintf(stderr, " WARNING : data_size is too large !\n " ); 
166              datasize  =  DEF_PACKET_SIZE; 
167          } 
168      } 
169       else  
170          datasize  =  DEF_PACKET_SIZE; 
171 
172      datasize  +=   sizeof (IcmpHeader); 
173 
174      icmp_data  =  ( char * )xmalloc(MAX_PACKET); 
175      recvbuf  =  ( char * )xmalloc(MAX_PACKET); 
176 
177       if  ( ! icmp_data) { 
178          fprintf(stderr, " HeapAlloc failed %d\n " ,GetLastError()); 
179          ExitProcess(STATUS_FAILED); 
180      } 
181 
182 
183      memset(icmp_data, 0 ,MAX_PACKET); 
184      fill_icmp_data(icmp_data,datasize); 
185 
186       //  
187       // 显示提示信息 
188       //  
189      fprintf(stdout, " \nPinging %s .\n\n " ,dest_ip); 
190 
191 
192       for ( int  i = 0 ;i < times; ++ i){ 
193           int  bwrote; 
194 
195          ((IcmpHeader * )icmp_data) -> i_cksum  =   0
196          ((IcmpHeader * )icmp_data) -> timestamp  =  GetTickCount(); 
197 
198          ((IcmpHeader * )icmp_data) -> i_seq  =  seq_no ++
199          ((IcmpHeader * )icmp_data) -> i_cksum  =  checksum((USHORT * )icmp_data,datasize); 
200 
201          bwrote  =  sendto(sockRaw,icmp_data,datasize, 0 ,( struct  sockaddr * ) & dest, sizeof (dest)); 
202           if  (bwrote  ==  SOCKET_ERROR){ 
203               if  (WSAGetLastError()  ==  WSAETIMEDOUT) { 
204                  printf( " Request timed out.\n " ); 
205                   continue
206              } 
207              fprintf(stderr, " sendto failed: %d\n " ,WSAGetLastError()); 
208              ExitProcess(STATUS_FAILED); 
209          } 
210           if  (bwrote  <  datasize ) { 
211              fprintf(stdout, " Wrote %d bytes\n " ,bwrote); 
212          } 
213          bread  =  recvfrom(sockRaw,recvbuf,MAX_PACKET, 0 ,( struct  sockaddr * ) & from, & fromlen); 
214           if  (bread  ==  SOCKET_ERROR){ 
215               if  (WSAGetLastError()  ==  WSAETIMEDOUT) { 
216                  printf( " Request timed out.\n " ); 
217                   continue
218              } 
219              fprintf(stderr, " recvfrom failed: %d\n " ,WSAGetLastError()); 
220              ExitProcess(STATUS_FAILED); 
221          } 
222           if ( ! decode_resp(recvbuf,bread, & from)) 
223              statistic ++ /*  成功接收的数目++  */  
224          Sleep( 1000 ); 
225 
226      } 
227 
228       /*  
229      Display the statistic result 
230       */  
231      fprintf(stdout, " \nPing statistics for %s \n " ,dest_ip); 
232      fprintf(stdout, "     Packets: Sent = %d,Received = %d, Lost = %d (%2.0f%% loss)\n " ,times, 
233          statistic,(times - statistic),( float )(times - statistic) / times * 100 ); 
234 
235 
236      WSACleanup(); 
237       return   0
238 
239 
240  /*  
241  The response is an IP packet. We must decode the IP header to locate 
242  the ICMP data 
243  */  
244  int  decode_resp( char   * buf,  int  bytes, struct  sockaddr_in  * from) { 
245 
246      IpHeader  * iphdr; 
247      IcmpHeader  * icmphdr; 
248      unsigned  short  iphdrlen; 
249 
250      iphdr  =  (IpHeader  * )buf; 
251 
252      iphdrlen  =  (iphdr -> h_len)  *   4  ;  //  number of 32-bit words *4 = bytes 
253 
254       if  (bytes  <  iphdrlen  +  ICMP_MIN) { 
255          printf( " Too few bytes from %s\n " ,inet_ntoa(from -> sin_addr)); 
256      } 
257 
258      icmphdr  =  (IcmpHeader * )(buf  +  iphdrlen); 
259 
260       if  (icmphdr -> i_type  !=  ICMP_ECHOREPLY) { 
261          fprintf(stderr, " non-echo type %d recvd\n " ,icmphdr -> i_type); 
262           return   1
263      } 
264       if  (icmphdr -> i_id  !=  (USHORT)GetCurrentProcessId()) { 
265          fprintf(stderr, " someone else's packet!\n " ); 
266           return   1
267      } 
268      printf( " %d bytes from %s: " ,bytes, inet_ntoa(from -> sin_addr)); 
269      printf( "  icmp_seq = %d.  " ,icmphdr -> i_seq); 
270      printf( "  time: %d ms  " ,GetTickCount() - icmphdr -> timestamp); 
271      printf( " \n " ); 
272       return   0
273 
274 
275 
276 
277  USHORT checksum(USHORT  * buffer,  int  size) { 
278 
279      unsigned  long  cksum = 0
280 
281       while (size  > 1 ) { 
282          cksum +=* buffer ++
283          size  -= sizeof (USHORT); 
284      } 
285 
286       if (size) { 
287          cksum  +=   * (UCHAR * )buffer; 
288      } 
289 
290      cksum  =  (cksum  >>   16 +  (cksum  &   0xffff ); 
291      cksum  +=  (cksum  >> 16 ); 
292       return  (USHORT)( ~ cksum); 
293 
294  /*  
295  Helper function to fill in various stuff in our ICMP request. 
296  */  
297  void  fill_icmp_data( char   *  icmp_data,  int  datasize){ 
298 
299      IcmpHeader  * icmp_hdr; 
300       char   * datapart; 
301 
302      icmp_hdr  =  (IcmpHeader * )icmp_data; 
303 
304      icmp_hdr -> i_type  =  ICMP_ECHO; 
305      icmp_hdr -> i_code  =   0
306      icmp_hdr -> i_id  =  (USHORT)GetCurrentProcessId(); 
307      icmp_hdr -> i_cksum  =   0
308      icmp_hdr -> i_seq  =   0
309 
310      datapart  =  icmp_data  +   sizeof (IcmpHeader); 
311       //  
312       //  Place some junk in the buffer. 
313       //  
314      memset(datapart, ' E ' , datasize  -   sizeof (IcmpHeader)); 
315 
316 
317 
318  /* ****************** 附: ping命令执行时显示的画面 **************\ 
319  *  C:\Documents and Settings\houzhijiang>ping 236.56.54.12      * 
320  *                                                               * 
321  *  Pinging 236.56.54.12 with 32 bytes of data:                  * 
322  *                                                               * 
323  *  Request timed out.                                           * 
324  *  Request timed out.                                           * 
325  *  Request timed out.                                           * 
326  *  Request timed out.                                           * 
327  *                                                               * 
328  *  Ping statistics for 236.56.54.12:                            * 
329  *     Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),    * 
330  *                                                               * 
331  \************************************************************** */  
332 
333  /* **************************************************************\ 
334  *  C:\Documents and Settings\houzhijiang>ping 127.0.0.1         * 
335  *                                                               * 
336  *  Pinging 127.0.0.1 with 32 bytes of data:                     * 
337  *                                                               * 
338  *  Reply from 127.0.0.1: bytes=32 time<1ms TTL=128              * 
339  *  Reply from 127.0.0.1: bytes=32 time<1ms TTL=128              * 
340  *  Reply from 127.0.0.1: bytes=32 time<1ms TTL=128              * 
341  *  Reply from 127.0.0.1: bytes=32 time<1ms TTL=128              * 
342  *                                                               * 
343  *  Ping statistics for 127.0.0.1:                               * 
344  *     Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),      * 
345  *  Approximate round trip times in milli-seconds:               * 
346  *     Minimum = 0ms, Maximum = 0ms, Average = 0ms               * 
347  *                                                               * 
348  \************************************************************** */  
349


你可能感兴趣的:(微软ping程序源代码完整版)