PING (Packet InterNet Groper) 是一个非常有用的命令,它可以用来测试两个主机之间的连通性.PING使用了ICMP回送请求与回送回答报文.PING是应用层直接使用网络层ICMP的一个例子.它没有通过运输层的TCP或UDP.
在Windows平台编程实现PING的最简单方法是调用Iphlpapi.dll这个动态链接库,引用以下几个函数:
1. IcmpCreateFile(); // opens a handle on which IPv4 ICMP echo requests can be issued.
2. IcmpSendEcho(); // sends an IPv4 ICMP echo request and returns any echo response replies.
// The call returns when the time-out has expired or the reply buffer is filled.
3. IcmpCloseHandle(); // closes a handle opened by a call to the IcmpCreateFile or Icmp6CreateFile functions.
以下是实现代码:
Code
1 // Ping.c
2 //
3 // 利用ICMP回送请求与回答报文模拟Ping命令
4 //
5 // Step:
6 // 1. Open ICMP handle
7 // 2. Sends an IPv4 ICMP echo request and returns any echo response replies.
8 // 3. Display the infomation for response echo.
9 // 4. Close ICMP handle
10 //
11 // Configuration before Build Solution:
12 // Project->Properties->Linker->Input->Addtional Dependencies : Iphlpapi.lib Ws2_32.lib
13 //
14 // Alvin
15 // 2008-2-18
16 //
17
18 #include <winsock2.h>
19 #include <iphlpapi.h>
20 #include <icmpapi.h>
21 #include <stdio.h>
22
23 int main( int argc, char ** argv )
24 {
25 /* 声明并初始化变量 */
26 HANDLE hIcmp = INVALID_HANDLE_VALUE;
27 unsigned long ulDestIpAddr = INADDR_NONE;
28 char sendBuffer [] = "Send Buffer";
29 LPVOID lpReplyBuffer = NULL;
30 int iReplySize = 0;
31 DWORD dwTimeout = 1000;
32 DWORD dwRetVal = 0;
33
34 /* 打开ICMP句柄 */
35 hIcmp = IcmpCreateFile ();
36 if ( INVALID_HANDLE_VALUE == hIcmp )
37 {
38 printf ( "Open ICMP failure!\n" );
39 return EXIT_FAILURE;
40 }
41
42 /* 验证命令行参数 */
43 if ( argc != 2 )
44 {
45 printf ( "Usage : %s IP Address\n", argv[0] );
46 IcmpCloseHandle( hIcmp );
47 return EXIT_FAILURE;
48 }
49
50 ulDestIpAddr = inet_addr ( argv[1] );
51 if ( *argv[1] == INADDR_NONE )
52 {
53 printf ( "Usage : %s IP Address\n", argv[0] );
54 IcmpCloseHandle( hIcmp );
55 return EXIT_FAILURE;
56 }
57
58 iReplySize = sizeof ( ICMP_ECHO_REPLY ) + sizeof ( sendBuffer );
59 lpReplyBuffer = malloc ( iReplySize );
60
61 /* 发送ICMP报文并等待回送请求 */
62 dwRetVal = IcmpSendEcho ( hIcmp, ulDestIpAddr, sendBuffer, sizeof(sendBuffer),
63 NULL, lpReplyBuffer, iReplySize, dwTimeout );
64 if ( 0 != dwRetVal )
65 {
66 // 利用一指针获取 Request Echo 的 ICMP_ECHO_REPLY 结构实例
67 PICMP_ECHO_REPLY pReplyEcho = (PICMP_ECHO_REPLY) lpReplyBuffer;
68
69 in_addr replyIpAddr;
70 replyIpAddr.S_un.S_addr = pReplyEcho->Address;
71 printf ( "Reply from : %s\n", inet_ntoa(replyIpAddr) );
72
73 if ( dwRetVal > 1 )
74 {
75 printf ( "Retrieved %d ICMP response message.\n", dwRetVal );
76 printf ( "----The infomation for the first message.----\n" );
77 }
78 else
79 {
80 printf ( "Retrieved %d ICMP reponse message.\n", dwRetVal );
81 printf ( "----The information for the message.----\n" );
82 }
83
84 printf ( "The status : %ld\n", pReplyEcho->Status );
85 printf ( "The reply data : %s\n", pReplyEcho->Data );
86 printf ( "The Roundtrip time : %ld milliseconds.\n", pReplyEcho->RoundTripTime );
87 }
88 else
89 {
90 printf ( "ICMP send failure.\n" );
91 printf ( "The IcmpSendEcho call error : %ld\n", GetLastError() );
92 IcmpCloseHandle( hIcmp );
93 return EXIT_FAILURE;
94 }
95
96 /* 关闭ICMP句柄 */
97 IcmpCloseHandle( hIcmp );
98
99 return EXIT_SUCCESS;
100
101 }
102