I. Data Structure
First, define the data structure of the IP data packet header Based on the IP data packet format (figure ).
Typedef struct tagiphdr // ip packet header <br/>{< br/> u_char vihl; // version (4) + header length (4) <br/> u_char TOS; // service type (8) <br/> short totlen; // total length (16) <br/> short ID; // ID (16) <br/> short flagoff; // flag (3) + slice offset (13) <br/> u_char TTL; // TTL (8) <br/> u_short checksum; // header checksum (16) <br/> in_addr iasrc; // source IP address (32) <br/> in_addr iadst; // target IP address (32) <br/>} iphdr, * piphdr;
Then, the data structure of ICMP is defined based on the ICMP return request and Response Message format.
Typedef struct tagicmphdr // ICMP send-back request and response with ICMP packets <br/>{< br/> u_char type; // type (8) <br/> u_char code; // code (8) <br/> u_short checksum; // checksum (16) <br/> u_short ID; // identifier (16) <br/> u_short seq; // No. (16) <br/> char data; // optional data <br/>} icmphdr, * picmphdr;
Then define the Data Length of the request delivery respectively
# Define req_datasize 32
Data Structure of request delivery
Typedef struct tagechorequest <br/>{< br/> icmphdr; <br/> DWORD dwtime; <br/> char CDATA [req_datasize]; <br/>} echorequest, * pechorequest;
Data Structure of ICMP return response
Typedef struct tagechoreply <br/>{< br/> iphdr; <br/> echorequest; <br/> char cfiller [256]; <br/>} ECHOREPLY, * pechoreply;
Ii. function implementation
(1) sendechorequest
The function is used to send a send-back request packet. Three static variables are defined first.
Static echorequest echoreq; // data structure of the send-back request
Static nid = 1; // identifier
Static nseq = 1; // serial number
Then fill in the delivery request information
Echoreq. icmphdr. type = icmp_echoreq; // type
Echoreq. icmphdr. Code = 0; // code
Echoreq. icmphdr. checksum = 0; // checksum
Echoreq. icmphdr. ID = NID ++; // identifier
Echoreq. icmphdr. seq = nseq ++; // serial number
Enter the data to be sent
For (I = 0; I <req_datasize; I ++)
{
Echoreq. CDATA [I] = ''+ I;
}
Save sending time
Echoreq. dwtime = gettickcount ();
Store data in the package and calculate the checksum
Echoreq. icmphdr. checksum = in_chsum (u_short *) & echoreq, sizeof (echorequest ));
Send a return request
Nret = sendto (S,
(Lpstr) & echoreq,
Sizeof (echorequest ),
0,
(Lpsockaddr) lpsttoaddr,
Sizeof (sockaddr_in ));
(2) recvechoreply
Function to receive response data
DWORD recvechoreply (socket S, lpsockaddr_in lpsafrom, u_char * pttl)
{
ECHOREPLY; // Response Data Structure
Int nret;
Int naddrlen = sizeof (sockaddr_in );
// Accept the response
Nret = recvfrom (S,
(Lpstr) & ECHOREPLY,
Sizeof (ECHOREPLY ),
0,
(Lpsockaddr) lpsafrom,
& Naddrlen );
// Check the returned value
If (nret = socket_error)
{
Reporterror ("recvfrom ()");
}
* Pttl = ECHOREPLY. iphdr. TTL; // obtain the TTL value.
Return (ECHOREPLY. echorequest. dwtime); // return the time used
}
(3) waitforechoreply
Function: waits for the child s to read data.
Int waitforechoreply (socket S)
{
Timeval timeout;
Fd_set readfds;
Readfds. fd_count = 1;
Readfds. fd_array [0] = s;
Timeout. TV _sec = 5;
Timeout. TV _usec = 0;
Return (select (1, & readfds, null, null, & timeout ));
}
(3) in_chsum
Function compute checksum
U_short in_chsum (u_short * ADDR, int Len)
{
Register int nleft = Len;
Register u_short * w = ADDR;
Register u_short answer;
Register int sum = 0;
While (nleft> 1)
{
Sum + = * w ++;
Nleft-= 2;
}
If (nleft = 1)
{
U_short u = 0;
* (U_char *) (& U) = * (u_char *) W;
Sum + = u;
}
Sum = (sum> 16) + (sum & 0 xFFFF );
Sum + = (sum> 16 );
Answer = ~ SUM;
Return (answer );
}
(4) Implementation of the Main Function
Step 1: Define the Winsock Data Structure wsadata and create the version 1.1
Step 2: Call wsastartup to initialize wsadata
Step 3: Call the Ping function
Step 4: Call wsacleanup to release Winsock
Void main (INT argc, char ** argv)
{
Wsadata;
Word wversionrequested = makeword (1, 1); // winsock1.1
Int nret;
// Command line parameter check
If (argc! = 2)
{
Fprintf (stderr, "/nusage: Ping Hostname/N ");
Return;
}
// Initialize Winsock
Nret = wsastartup (wversionrequested, & wsadata );
If (nret)
{
Fprintf (stderr, "/nerror initializing Winsock/N ");
Return;
}
If (wsadata. wversion! = Wversionrequested)
{
Fprintf (stderr, "/nwinsock version not supported/N ");
Return;
}
// Call the Ping function
Ping (argv [1]);
// Ping ("www.sina.com ");
// Release Winsock
Wsacleanup ();
}
(5) Ping
Function: implements the Ping function.
Define the data used by the function
Socket rawsocket; // original socket
Lphostent lphost; // host information
Sockaddr_in sadest; // target address
Sockaddr_in sasrc; // Source Address
DWORD dwtimesent; // sending time
DWORD dwelapsed; // Delay Time
Then create an original socket
Create an original set of interfaces with the ICMP protocol
Rawsocket = socket (af_inet, sock_raw, ipproto_icmp );
Obtain from the target address entered by the user
Lphost = gethostbyname (pstrhost );
Set the target set interface address
Sadest. sin_addr.s_addr = * (u_long far *) (lphost-> h_addr ));
Sadest. sin_family = af_inet;
Sadest. sin_port = 0;
Output the prompt message of the Ping program.
Printf ("/npinging % s [% s] With % d bytes of data:/N ",
Pstrhost,
Inet_ntoa (sadest. sin_addr ),
Req_datasize );
Send an ICMP return request
Sendechorequest (rawsocket, & sadest );
Use select () to wait for receiving the response data
Waitforechoreply (rawsocket );
Receive response
Dwtimesent = recvechoreply (rawsocket, & sasrc, & cttl );
Calculate the transmission time and output the prompt.
Dwelapsed = gettickcount ()-dwtimesent;
Promised Response Information
Printf ("/nreply from: % s: bytes = % d time = % ldms TTL = % d ",
Inet_ntoa (sasrc. sin_addr ),
Req_datasize,
Dwelapsed,
Cttl );
}
// Close the socket
Nret = closesocket (rawsocket );
Appendix: program source code
// Ping. h <br/> // defines the structure of the IP address and ICMP header in this header file <br/> # pragma pack (1) <br/> # define ICMP_ECHOREPLY 0 <br/> # define icmp_echoreq 8 <br/> typedef struct tagiphdr // ip packet header <br/>{< br/> u_char vihl; // version (4) + header length (4) <br/> u_char TOS; // service type (8) <br/> short totlen; // total length (16) <br/> short ID; // ID (16) <br/> short flagoff; // sign (3) + part offset (13) <br/> u_char TTL; // TTL (8) <br/> u_short checksum; // header checksum (16) <br/> in_addr iasrc; // source IP address (32) <br/> in_addr iadst; // target IP address (32) <br/>} iphdr, * piphdr; <br/> typedef struct tagicmphdr // ICMP return request and ICMP packet <br/>{< br/> u_char type; // type (8) <br/> u_char code; // code (8) <br/> u_short checksum; // checksum (16) <br/> u_short ID; // identifier (16) <br/> u_short seq; // serial number (16) <br/> char data; // optional data <br/>} icmphdr, * picmphdr; <br/> // The length of the data returned by the request <br/> # define req_datasize 32 <br/> // the data structure of the ICMP return request <br/> typestrudef CT tagechorequest <br />{< br/> icmphdr; <br/> DWORD dwtime; <br/> char CDATA [req_datasize]; <br/>} echorequest, * pechorequest; <br/> // ICMP return response <br/> typedef struct tagechoreply <br/> {<br/> iphdr; <br/> echorequest; <br/> char cfiller [256]; <br/>} ECHOREPLY, * pechoreply; <br/> # pragma pack ()
// Ping. CPP <br/> // implement the simple Ping function <br/> # include <stdio. h> <br/> # include <stdlib. h> <br/> # include <Winsock. h> <br/> # include "Ping. H "<br/> void Ping (lpcstr pstrhost); <br/> void reporterror (lpcstr pstrfrom); <br/> int waitforechoreply (socket S ); <br/> u_short in_chsum (u_short * ADDR, int Len); <br/> // ICMP return request and response function declaration <br/> int sendechorequest (socket, lpsockaddr_in ); <br/> DWORD recvechoreply (socket, lpsockad Dr_in, u_char *); <br/> // Main Program <br/> void main (INT argc, char ** argv) <br/>{< br/> wsadata; <br/> word wversionrequested = makeword (1, 1); // winsock1.1 <br/> int nret; </P> <p> // command line parameter check <br/> If (argc! = 2) <br/>{< br/> fprintf (stderr, "/nusage: Ping Hostname/N"); <br/> return; <br/>}< br/> // initialize Winsock <br/> nret = wsastartup (wversionrequested, & wsadata); <br/> If (nret) <br/>{< br/> fprintf (stderr, "/nerror initializing Winsock/N"); <br/> return; <br/>}< br/> If (wsadata. wversion! = Wversionrequested) <br/>{< br/> fprintf (stderr, "/nwinsock version not supported/N"); <br/> return; <br/>}< br/> // call the Ping function <br/> Ping (argv [1]); <br/> // Ping ("www.sina.com "); <br/> // release Winsock <br/> wsacleanup (); <br/>}< br/> void Ping (lpcstr pstrhost) <br/> {<br/> socket rawsocket; // original socket <br/> lphostent lphost; // host information <br/> sockaddr_in sadest; // target address <br/> sockaddr_in sasrc; // source address <br/> DWORD dwtimesent; // Sending time <br/> DWORD dwelapsed; // delay time <br/> u_char cttl; <br/> int nloop; <br/> int nret; <br/> // create an original set of interfaces <br/> rawsocket = socket (af_inet, sock_raw, ipproto_icmp); <br/> If (rawsocket = socket_error) <br/>{< br/> reporterror ("socket ()"); <br/> return; <br/>}< br/> lphost = gethostbyname (pstrhost ); <br/> If (lphost = NULL) <br/> {<br/> fprintf (stderr, "/nhost not found: % s/n", pstrhost ); <br/> return; <br />}< Br/> // set the target set of interface addresses <br/> sadest. sin_addr.s_addr = * (u_long far *) (lphost-> h_addr); <br/> sadest. sin_family = af_inet; <br/> sadest. sin_port = 0; <br/> // output the Ping program prompt information <br/> printf ("/npinging % s [% s] With % d bytes of data: /n ", <br/> pstrhost, <br/> inet_ntoa (sadest. sin_addr), <br/> req_datasize); <br/> // control the number of Ping executions <br/> for (nloop = 0; nloop <4; nloop ++) <br/>{< br/> // send an ICMP return request <br/> sendechoreques T (rawsocket, & sadest); <br/> // use select () to wait for data to be sent back <br/> nret = waitforechoreply (rawsocket ); <br/> If (nret = socket_error) <br/>{< br/> reporterror ("select ()"); <br/> break; <br/>}< br/> If (! Nret) <br/>{< br/> printf ("/ntimeout/N"); <br/> break; <br/>}< br/> // receives a response <br/> dwtimesent = recvechoreply (rawsocket, & sasrc, & cttl); <br/> // calculates the transmission time, and output the prompt message <br/> dwelapsed = gettickcount ()-dwtimesent; <br/> printf ("/nreply from: % s: bytes = % d time = % ldms TTL = % d ", <br/> inet_ntoa (sasrc. sin_addr), <br/> req_datasize, <br/> dwelapsed, <br/> cttl); <br/>}< br/> printf ("/N "); <br/> // close the socket <br/> nret = closesock Et (rawsocket); <br/> If (nret = socket_error) <br/>{< br/> reporterror ("closesocket ()"); <br/>}< br/> int sendechorequest (socket S, lpsockaddr_in lpsttoaddr) <br/>{< br/> static echorequest echoreq; // data structure of the send-back request <br/> static nid = 1; // identifier <br/> static nseq = 1; // No. <br/> int nret; <br/> int I; <br/> // enter the return request information <br/> echoreq. icmphdr. type = icmp_echoreq; // type <br/> echoreq. icmphdr. code = 0; // Code <br /> Echoreq. icmphdr. checksum = 0; // checksum <br/> echoreq. icmphdr. id = NID ++; // identifier <br/> echoreq. icmphdr. SEQ = nseq ++; // serial number <br/> // enter the data to be sent <br/> for (I = 0; I <req_datasize; I ++) <br/> {<br/> echoreq. CDATA [I] = ''+ I; <br/>}< br/> // Save the sending time <br/> echoreq. dwtime = gettickcount (); <br/> // store data in the package and calculate the checksum. <br/> echoreq. icmphdr. checksum = in_chsum (u_short *) & echoreq, sizeof (echorequest); <br/> // send a return request <br/> Nret = sendto (S, <br/> (lpstr) & echoreq, <br/> sizeof (echorequest), <br/> 0, <br/> (lpsockaddr) lpsttoaddr, <br/> sizeof (sockaddr_in); <br/> If (nret = socket_error) <br/>{< br/> reporterror ("sendto () "); <br/>}< br/> return nret; <br/>}< br/> DWORD recvechoreply (socket S, lpsockaddr_in lpsafrom, u_char * pttl) <br/> {<br/> ECHOREPLY; // the data structure of the send-back response <br/> int nret; <br/> int naddrlen = sizeof (sockaddr_in ); <Br/> // receives the delivery response <br/> nret = recvfrom (S, <br/> (lpstr) & ECHOREPLY, <br/> sizeof (ECHOREPLY ), <br/> 0, <br/> (lpsockaddr) lpsafrom, <br/> & naddrlen ); <br/> // check the returned value <br/> If (nret = socket_error) <br/> {<br/> reporterror ("recvfrom ()"); <br/>}< br/> * pttl = ECHOREPLY. iPhone dr. TTL; // obtain the TTL value <br/> return (ECHOREPLY. echorequest. dwtime); // returned time <br/>}< br/> void reporterror (lpcstr pstrfrom) <br/>{< br/> fprintf (stde RR, "/n % d error:/N", wsagetlasterror ()); <br/>}< br/> // wait for the child s to read data <br/> int waitforechoreply (socket S) <br/>{< br/> timeval timeout; <br/> fd_set readfds; <br/> readfds. fd_count = 1; <br/> readfds. fd_array [0] = s; <br/> timeout. TV _sec = 5; <br/> timeout. TV _usec = 0; <br/> return (select (1, & readfds, null, null, & timeout )); <br/>}< br/> u_short in_chsum (u_short * ADDR, int Len) <br/>{< br/> Register int Nleft = Len; <br/> Register u_short * w = ADDR; <br/> Register u_short answer; <br/> Register int sum = 0; <br/> while (nleft> 1) <br/>{< br/> sum + = * w ++; <br/> nleft-= 2; <br/>}< br/> If (nleft = 1) <br/>{< br/> u_short u = 0; <br/> * (u_char *) (& U) = * (u_char *) W; <br/> sum + = u; <br/>}< br/> sum = (sum> 16) + (sum & 0 xFFFF); <br/> sum + = (sum> 16); <br/> answer = ~ SUM; <br/> return (answer); <br/>}