{
IcmpHeader*icmp_hdr ; char*datapart ;
icmp_hdr=(IcmpHeader*)icmp_data ; icmp_hdr->i_type=ICMP_ECHO ; icmp_hdr->i_code=0 ;
icmp_hdr->i_id=(USHORT)GetCurrentProcessId(); icmp_hdr->i_cksum=0 ; icmp_hdr->i_seq=0 ; icmp_hdr->timestamp=ts;
datapart=icmp_data+sizeof(IcmpHeader);
memset(datapart,'E',datasize-sizeof(IcmpHeader)); }
(2)USHORT checksum(USHORT*buffer,int size); //计算ICMP首部校验和
USHORT checksum(USHORT*buffer,int size) {
unsigned long cksum=0 ; while(size>1) {
cksum+=*buffer++; size-=sizeof(USHORT); }
if(size) {
cksum+=*(UCHAR*)buffer ; }
cksum=(cksum>>16)+(cksum&0xffff); cksum+=(cksum>>16); return(USHORT)(~cksum); }
(3)int decode_resp(char*buf,int bytes,struct sockaddr_in*from); //解析收到的数据包
int decode_resp(char*buf,int bytes,struct sockaddr_in*from) {
IpHeader*iphdr ; IcmpHeader*icmphdr ;
unsigned short iphdrlen ; iphdr=(IpHeader*)buf ;
iphdrlen=(iphdr->h_len)*4 ; if(bytes cout<<\ } icmphdr=(IcmpHeader*)(buf+iphdrlen); if(icmphdr->i_type!=ICMP_ECHOREPLY) { cout<<\ return 1 ; } if(icmphdr->i_id!=(USHORT)GetCurrentProcessId()) { cout<<\ return 1 ; } bytes-=32; cout<<\ cout<<\ cout<<\ return 0 ; } 4.主函数的具体流程(int main( 1) 原始套接字的创建: SOCKET sockRaw ; sockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED; if(sockRaw==INVALID_SOCKET) { cout<<\ ExitProcess(STATUS_FAILED); } 2)定义套接字选项 bread=setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));如果没有出现错误,setsocket返回值为0; 3)定义sockaddr_in类型的dest,from两个变量。 sock addr_in结构是专门被Windows Sockets用来详细说明套接字连接地址的。 struct sockaddr_in dest,from; struct hostent*hp; char*dest_ip ;//用来放要ping的目的地址。 if(hp!=NULL) memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); else dest.sin_addr.s_addr=addr ; if(hp) dest.sin_family=hp->h_addrtype ; else dest.sin_family=AF_INET ; dest_ip=inet_ntoa(dest.sin_addr); 4)创建ICMP包 datasize+=sizeof(IcmpHeader); icmp_data=(char*)xmalloc(MAX_PACKET); recvbuf=(char*)xmalloc(MAX_PACKET); if(!icmp_data) { cout<<\ ExitProcess(STATUS_FAILED); } memset(icmp_data,0,MAX_PACKET); fill_icmp_data(icmp_data,datasize,ts);//函数已经在前面定义 5)发送和接收ICMP包 for(int i=0;i < packnum;++i) { int bwrote ; ((IcmpHeader*)icmp_data)->i_cksum=0 ; ((IcmpHeader*)icmp_data)->timestamp=GetTickCount(); ((IcmpHeader*)icmp_data)->i_seq=seq_no++; ((IcmpHeader*)icmp_data)->i_cksum=checksum((USHORT*)icmp_data,datasize); //checksum用来计算校验和,函数已经在前面定义。 bwrote=sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,sizeof(dest));//sendto用来发送数据到指定的地址。 if(bwrote==SOCKET_ERROR) { if(WSAGetLastError()==WSAETIMEDOUT) { cout<<\ continue ; } cout<<\ ExitProcess(STATUS_FAILED); } if(bwrote cout<<\ } bread=recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from,&fromlen);// recvfrom用来接收数据并保存 //bread changed if(bread==SOCKET_ERROR) { if(WSAGetLastError()==WSAETIMEDOUT) { cout<<\ continue ; } cout<<\ ExitProcess(STATUS_FAILED); } if(!decode_resp(recvbuf,bread,&from)) //decode_resp用来解析收到的ICMP数据包,函数已经在前面定义。 statistic++; Sleep(1000); } 6)输出统计结果 五、程序实现的结果: 在运行程序时,要选择菜单“工程→设置 →Link”,在对象/库模块中添加Ws2_32.lib,如下图: 在DOS窗口下到ping.exe的当前目录下,输入ping,如下图:

