ping with ICMP

来源:互联网 发布:东方网络什么时候复牌 编辑:程序博客网 时间:2024/05/01 19:59

ICMP测试网络是否可达:

我们都知道为了能够有效的通信,在进行通信之前要先确认通信对象是否可达,如果通信对象是不可达的,那么进行数据的传输是没有意义的,所以我们可以使用ICMP【Internet control manage protocol】来测试是否连通。我们知道ICMP报文是跟着IP报文一起传输的,也就是说ICMP报文时IP中的一部分,而且在请求回显的数据中包含着IP数据包和ICMP报文。

其通信模型是:


所以可以看出,其中每一包至少包含32个字节,其中的20字节的IP首部以及12字节的ICMP报文,所以其IP首部的数据结构是:

struct IP_Head{unsigned char versionandLenght;unsigned char serviceType;unsigned short totalLenght;unsigned short IPId;unsigned short frag_and_flags;unsigned char TTL;    unsigned char protocol;unsigned short checkNum;unsigned int souIP;unsigned int dstIP;};

其中ICMP的结构是:

struct ICMP_Head{BYTE icmpType;BYTE icmpCode;USHORT checkNum;USHORT icmpId;USHORT icmpSeq;ULONG timeStamp;};

下面是对应的代码:

1:加载DLL:#pragmacomment(lib,"ws2_32.lib")

2:创建socket,创建之前要先配置环境如:

WSAStartup(MAKEWORD(2,2),&wsadata);socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);


3:创建目标地址:

         h=gethostbyname(argv[1]);         memcpy(&(destAddr.sin_addr),h->h_addr,h->h_length);         destAddr.sin_family=h->h_addrtype;


4:设置延迟:

setsockopt(sockfd,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,(char*)&recvtime,sizeof(recvtime));


5:创建ICMP报文:

    Char  buf[MAX_PACKET];ICMP_Head *icmphead=NULL;    char *datapart=NULL;     icmphead = (ICMP_Head*)buf;    icmphead->icmpType =ICMP_PROTOCOL;          icmphead->icmpCode =0;                 icmphead->checkNum =0;     icmphead->icmpId =(USHORT)GetCurrentProcessId();        icmphead->timeStamp=0;       icmphead->icmpSeq=0;             datapart = buf + sizeof(ICMP_Head);       for(inti=0;i<(DEF_PACKET_SIZE-sizeof(ICMP_Head));i++,datapart++)         *datapart=NULL;


 

6:发送ICMP报文:

sendto(sockfd,sendbuf,DEF_PACKET_SIZE,0,(sockaddr*)&destAddr,sizeof(sockaddr));


 

7:获取回显信息:

recvfrom(sockfd,recvbuf,MAX_PACKET,0,(sockaddr*)&fromAddr,&len);


    8:解析回显信息:

        IP_Head*idHead=(IP_Head*)recvbuf;             ICMP_Head*icmp_head=(ICMP_Head*)(recvbuf+sizeof(IP_Head));


    9:关闭socket:

  

     Closesocket(sockfd);       WSACleanup();

     在此次的设计过程中,socket的创建在主函数中创建

    ICMP报文的初始化在fill_ICMP()函数中初始化

     发送报文和接收报文在process_ICMP()函数中

     解析报文在decode_ICMP()函数中

     校验和计算在checksum函数中

整个程序的源代码是:

#include <iostream>#include <WINSOCK2.H>#pragma comment(lib,"ws2_32.lib")#define ICMP_PROTOCOL 8#define ICMP_CODE 0#define ICMP_MIN 8             #define DEF_PACKET_SIZE 32     #define DEF_PACKET_NUMBER 10     #define MAX_PACKET 64        using namespace std;/************************************************************************//*          下面的是IP首部的20个字节,这在接收ICMP回显时使用            *//************************************************************************/struct IP_Head{unsigned char versionandLenght;unsigned char serviceType;unsigned short totalLenght;unsigned short IPId;unsigned short frag_and_flags;unsigned char TTL;    unsigned char protocol;unsigned short checkNum;unsigned int souIP;unsigned int dstIP;};/************************************************************************//* 下面是ICMP的协议信息                                                 *//************************************************************************/struct ICMP_Head{BYTE icmpType;BYTE icmpCode;USHORT checkNum;USHORT icmpId;USHORT icmpSeq;ULONG timeStamp;};float recv_packet=0;void fill_ICMP(char *buf){   ICMP_Head *icmphead=NULL;     char *datapart=NULL;     icmphead = (ICMP_Head*)buf;     icmphead->icmpType =ICMP_PROTOCOL;           icmphead->icmpCode =0;                  icmphead->checkNum =0;icmphead->icmpId = (USHORT)GetCurrentProcessId();  icmphead->timeStamp=0;icmphead->icmpSeq=0;    datapart = buf + sizeof(ICMP_Head);        for(int i=0;i<(DEF_PACKET_SIZE-sizeof(ICMP_Head));i++,datapart++)         *datapart=NULL;}unsigned short checksum(unsigned short *buffer, int size){unsigned long cksum=0;while(size >1){cksum+=*buffer++;size -=sizeof(unsigned short);}if(size ){cksum += *(unsigned char*)buffer;}cksum = (cksum >> 16) + (cksum & 0xffff);cksum += (cksum >>16);return (unsigned short)(~cksum);}void decode_ICMP(const char *recvbuf,int byt,sockaddr_in *from){ recv_packet++;     IP_Head *idHead=(IP_Head*)recvbuf; ICMP_Head *icmp_head=(ICMP_Head*)(recvbuf+sizeof(IP_Head)); cout<<"Reply from "<<inet_ntoa(from->sin_addr); cout<<"  "<<byt<<" bytes"; cout<<" time: "<<GetTickCount()-icmp_head->timeStamp<<" ms "; cout<<" seq="<<icmp_head->icmpSeq; cout<<" TTL="<<static_cast<int>(idHead->TTL); cout<<endl;}void process_ICMP(SOCKET sockfd,sockaddr_in fromAddr,sockaddr_in destAddr){char recvbuf[MAX_PACKET];char sendbuf[DEF_PACKET_SIZE];    memset(sendbuf,0,DEF_PACKET_SIZE);fill_ICMP(sendbuf);for (int i=0; i<DEF_PACKET_NUMBER; ++i){((ICMP_Head*)sendbuf)->checkNum=0;((ICMP_Head*)sendbuf)->icmpSeq=i+1;((ICMP_Head*)sendbuf)->timeStamp= GetTickCount();((ICMP_Head*)sendbuf)->checkNum=checksum((unsigned short*)sendbuf,32);int bsend;bsend=sendto(sockfd,sendbuf,DEF_PACKET_SIZE,0,(sockaddr*)&destAddr,sizeof(sockaddr));if (bsend==SOCKET_ERROR){if (WSAGetLastError() == WSAETIMEDOUT)   {              cout<<"Request timed out."<<endl;              continue;   }   else    {   cout<<"sendto( ) failed:"<<WSAGetLastError();   cout<<endl;   return;   }}cout<<"send success!data is:"<<((ICMP_Head*)sendbuf)->icmpSeq;cout<<"  send "<<bsend<<" byte"<<endl;int len=sizeof(sockaddr);int brecv=recvfrom(sockfd,recvbuf,MAX_PACKET,0,(sockaddr*)&fromAddr,&len);if (brecv==SOCKET_ERROR){  if (WSAGetLastError() == WSAETIMEDOUT)   {                 cout<<"Request timed out."<<endl;                 continue;   }           cout<<"recvfrom() failed: "<<WSAGetLastError()<<__LINE__<<endl;   cout<<endl;           return;}decode_ICMP(recvbuf,brecv,&fromAddr);Sleep(1000);}cout<<"all send "<<DEF_PACKET_NUMBER<<" packet ,obtain "<<recv_packet<<endl;cout<<"loss packet is %"<<(1-recv_packet/DEF_PACKET_NUMBER)*100<<endl;}int main(int argc,const char *argv[]){WSADATA wsadata;SOCKET sockfd;hostent *h;sockaddr_in fromAddr,destAddr;if (WSAStartup(MAKEWORD(2,2),&wsadata)!=0){cout<<"WSAStartup fail!"<<endl;cout<<"errno="<<WSAGetLastError()<<endl;return 1;}if (argc<=1){cout<<"please input params!"<<endl;return 1;}h=gethostbyname(argv[1]);    if (h==NULL)    {cout<<"gethosybyname error!"<<endl;return 1;    }memcpy(&(destAddr.sin_addr),h->h_addr,h->h_length);destAddr.sin_family=h->h_addrtype;//destAddr.sin_port=htons(0);cout<<"address:"<<inet_ntoa(destAddr.sin_addr)<<endl;sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);if (sockfd==SOCKET_ERROR){cout<<"socket fail!"<<endl;return 1;}int timeout=1000;int bread=setsockopt(sockfd,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(timeout));if (bread==SOCKET_ERROR){cout<<"setsockopt read fail!"<<endl;return 1;}int recvtime=500;int bwrite=setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,(char *)&recvtime,sizeof(recvtime));if (bwrite==SOCKET_ERROR){cout<<"setockopt write fail!"<<endl;return 1;}    process_ICMP(sockfd,fromAddr,destAddr);closesocket(sockfd);WSACleanup();return 0;}










原创粉丝点击