用C++自己实现Ping程序
发布时间:2020-12-16 07:44:42 所属栏目:百科 来源:网络整理
导读:今天PHP站长网 52php.cn把收集自互联网的代码分享给大家,仅供参考。 //// Ping.h// #pragma pack(1) #define ICMP_ECHOREPLY 0#define ICMP_ECHOREQ 8 // IP Header -- RFC 791typedef struct tagIPHDR{ u_char VIHL; //
以下代码由PHP站长网 52php.cn收集自互联网 现在PHP站长网小编把它分享给大家,仅供参考 // // Ping.h // #pragma pack(1) #define ICMP_ECHOREPLY 0 #define ICMP_ECHOREQ 8 // IP Header -- RFC 791 typedef struct tagIPHDR { u_char VIHL; // Version and IHL u_char TOS; // Type Of Service short TotLen; // Total Length short ID; // Identification short FlagOff; // Flags and Fragment Offset u_char TTL; // Time To Live u_char Protocol; // Protocol u_short Checksum; // Checksum struct in_addr iaSrc; // Internet Address - Source struct in_addr iaDst; // Internet Address - Destination }IPHDR,*PIPHDR; // ICMP Header - RFC 792 typedef struct tagICMPHDR { u_char Type; // Type u_char Code; // Code u_short Checksum; // Checksum u_short ID; // Identification u_short Seq; // Sequence //char Data; // Data }ICMPHDR,*PICMPHDR; #define REQ_DATASIZE 36 #define REQ_datasize2 30 #define Renum 66 // ICMP Echo Request typedef struct tagECHOREQUEST { ICMPHDR icmpHdr; DWORD dwTime; char cData[REQ_DATASIZE]; }ECHOREQUEST,*PECHOREQUEST; typedef struct tempECHREQUEST{ ICMPHDR icmpHdr; DWORD dwTime; char cData[Renum]; }tempECHREQUEST,*PtempECHOREQUEST; typedef struct tempECHREQUEST2{ ICMPHDR icmpHdr; DWORD dwTime; char cData[Renum+8]; }tempecho,*Ptempecho; // ICMP Echo Reply typedef struct tagECHOREPLY { IPHDR ipHdr; ECHOREQUEST echoRequest; char cFiller[256]; }ECHOREPLY,*PECHOREPLY; //IP echo request typedef struct tagIPEchorequest{ IPHDR ipHeader; ECHOREQUEST icmp_data; }IPECHOREQUET,*PIPECHOREQUEST; typedef struct tagIPEchoTwo{ IPHDR ipHeader; char cData[REQ_datasize2]; }IPEchoTwo,*PIPEchoTwo; typedef struct tagIPechoTwo2{ IPHDR ipHeader; char cData[REQ_datasize2+8]; }IPechotwo2,*PIPechotwo2; //ip echo reply typedef struct tagIPREPLY{ IPHDR ipHdr; ECHOREQUEST echoRequest; char cFiller[256]; }IPECHOREPLY,*PIPECHOREPLY; #pragma pack() // PING.C -- Ping program using ICMP and RAW Sockets // #include <stdio.h> #include <stdlib.h> #include <winsock2.h> #include "ws2tcpip.h" #include <iostream> #pragma comment(lib,"WS2_32.lib") #include "ping.h" // Internal Functions void Ping(LPCSTR pstrHost); void ReportError(LPCSTR pstrFrom); int WaitForEchoReply(SOCKET s); u_short in_cksum(u_short *addr,int len); // ICMP Echo Request/Reply functions int SendEchoRequest(SOCKET,LPSOCKADDR_IN); DWORD RecvEchoReply(SOCKET,LPSOCKADDR_IN,u_char *); //IP internal function void sendIP(LPCSTR pstrHost); int SendIPEchoRequestFragmentTwo(SOCKET s,LPSOCKADDR_IN lpstToAddr); int SendIPEchoRequest(SOCKET,LPSOCKADDR_IN); static short nId = 1; static short nSeq = 1; static short ip_id = rand()%256; static char DataToSend[Renum]; static short flag1 = 0; //标记,0标识不重复,1标识有重复 static short flag2 = 0; //标记,0标识顺序,1标识逆序 char sourseIP[16]; // main() void main(int argc,char **argv) { WSADATA wsaData; WORD wVersionRequested = MAKEWORD(2,1); int nRet; // Check arguments if (argc != 2) { fprintf(stderr,"nUsage: ping hostnamen"); return; } // Init WinSock如果成功,则返回0 nRet = WSAStartup(wVersionRequested,&wsaData); if (nRet) { fprintf(stderr,"nError initializing WinSockn"); return; } // Check version if (wsaData.wVersion != wVersionRequested) { fprintf(stderr,"nWinSock version not supportedn"); return; } printf(" n输入目的主机IP地址:n"); gets(argv[1]); sendIP(argv[1]); system("pause"); // Free WinSock WSACleanup(); } // Ping() // Calls SendEchoRequest() and // RecvEchoReply() and prints results void Ping(LPCSTR pstrHost) { SOCKET rawSocket; //原始套接字 LPHOSTENT lpHost; //保存目的主机信息 struct sockaddr_in saDest; //目的主机 struct sockaddr_in saSrc; //源主机 DWORD dwTimeSent; //发送时间 DWORD dwElapsed; //时间间隔 u_char cTTL; //ttl int nLoop; //发送循环的ping的次数 int nRet; // Create a Raw socket rawSocket = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP); if (rawSocket == SOCKET_ERROR) { ReportError("socket()"); return; } // Lookup host lpHost = gethostbyname(pstrHost); if (lpHost == NULL) { fprintf(stderr,"nHost not found: %sn",pstrHost); return; } // Setup destination socket address saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr)); saDest.sin_family = AF_INET; saDest.sin_port = 0; // Tell the user what we're doing printf("nPinging %s [%s] with %d bytes of data:n",pstrHost,inet_ntoa(saDest.sin_addr),REQ_DATASIZE); // Ping multiple times for (nLoop = 0; nLoop < 4; nLoop++) { // Send ICMP echo request SendEchoRequest(rawSocket,&saDest); // Use select() to wait for data to be received nRet = WaitForEchoReply(rawSocket); if (nRet == SOCKET_ERROR) { ReportError("select()"); break; } if (!nRet) { printf("nTimeOut"); break; } // Receive reply dwTimeSent = RecvEchoReply(rawSocket,&saSrc,&cTTL); // Calculate elapsed time dwElapsed = GetTickCount() - dwTimeSent; printf("nReply from: %s: bytes=%d time=%ldms TTL=%d",inet_ntoa(saSrc.sin_addr),REQ_DATASIZE,dwElapsed,cTTL); } printf("n"); nRet = closesocket(rawSocket); if (nRet == SOCKET_ERROR) ReportError("closesocket()"); } /* 使用原始套接字编程,实现分片IP数据包的构造,能够用两个IP分片 构成ICMP ECHO请求,并接收另一方协议栈返回的ICMP应答。 */ void sendIP(LPCSTR pstrHost){ SOCKET rawSocket; //原始套接字 LPHOSTENT lpHost; //保存目的主机信息 struct sockaddr_in saDest; //目的主机 struct sockaddr_in saSrc; //源主机 DWORD dwTimeSent; //发送时间 DWORD dwElapsed; //时间间隔 u_char cTTL; //ttl //int nLoop; //发送循环的ping的次数,这里是需要分片的片数目 int nRet; // Create a Raw socket创建IP数据包的套接字 rawSocket = socket(AF_INET,IPPROTO_IP); if (rawSocket == SOCKET_ERROR) { ReportError("socket()"); return; } //设置套接字选项 BOOL blflag = true; int set_return = setsockopt(rawSocket,IPPROTO_IP,IP_HDRINCL,(char*)&blflag,sizeof(blflag)); if (set_return) { printf("设置选项失败!%d",set_return); return; } if (set_return == SOCKET_ERROR) { printf("设置选项错误!"); return; } // Lookup host lpHost = gethostbyname(pstrHost); if (lpHost == NULL) { fprintf(stderr,pstrHost); return; } printf("n输入本机IP地址:n"); gets(sourseIP); // Setup destination socket address saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr)); saDest.sin_family = AF_INET; saDest.sin_port = 0; // Tell the user what we're doing printf("n发送数据包(2个分片第一片)到 %s --[%s] 数据大小是%d :n",REQ_DATASIZE); // Ping multiple times printf("n分片发送,不重叠输入0,重叠输入1:n"); std::cin>>flag1; printf("n分片发送,两片顺序发送输入0,逆序发送输入1:n"); std::cin>>flag2; if (flag2==0) { SendIPEchoRequest(rawSocket,&saDest); SendIPEchoRequestFragmentTwo(rawSocket,&saDest); } if (flag2==1) { SendIPEchoRequestFragmentTwo(rawSocket,&saDest); SendIPEchoRequest(rawSocket,&saDest); } // Use select() to wait for data to be received nRet = WaitForEchoReply(rawSocket); if (nRet == SOCKET_ERROR) ReportError("select()"); if (!nRet) printf("nTimeOut"); // Receive reply////////////////////////////////////////////// dwTimeSent = RecvEchoReply(rawSocket,&cTTL); printf("n检查收到的时间:%dn",dwTimeSent); // Calculate elapsed time dwElapsed = GetTickCount() - dwTimeSent; printf("n当前的时间 :%dn",GetTickCount()); printf("nReply from: %s: bytes=%d time=%ldms TTL=%d",cTTL); printf("n"); nRet = closesocket(rawSocket); if (nRet == SOCKET_ERROR) ReportError("closesocket()"); } // SendEchoRequest() // Fill in echo request header // and send to destination int SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr) { static ECHOREQUEST echoReq; static short nId = 1; static short nSeq = 1; int nRet; // Fill in echo request echoReq.icmpHdr.Type = ICMP_ECHOREQ; echoReq.icmpHdr.Code = 0; echoReq.icmpHdr.Checksum = 0; echoReq.icmpHdr.ID = nId++; echoReq.icmpHdr.Seq = nSeq++; // Fill in some data to send for (nRet = 0; nRet < REQ_DATASIZE; nRet++) echoReq.cData[nRet] = 'a'+nRet; // printf("nn%dnn",sizeof(echoReq)); // Save tick count when sent echoReq.dwTime = GetTickCount(); // Put data in packet and compute checksum echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq,sizeof(ECHOREQUEST)); // Send the echo request nRet = sendto(s,/* socket */ (LPSTR)&echoReq,/* buffer */ sizeof(ECHOREQUEST),/* flags */ (LPSOCKADDR)lpstToAddr,/* destination */ sizeof(SOCKADDR_IN)); /* address length */ if (nRet == SOCKET_ERROR) ReportError("sendto()"); return (nRet); } /*发送第一片数据*/ int SendIPEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr){ static IPECHOREQUET ipechoReq; //第一片的IP头部处理过程 ipechoReq.ipHeader.VIHL = 0x45; //版本是4,首部长度是5 ipechoReq.ipHeader.TOS = 0x0; //由标准组织分配 ipechoReq.ipHeader.ID = ip_id; //ip的标识(一唯),这里一定要注意,ip标识不变,同一个数据包的两片 ipechoReq.ipHeader.TTL = 64; //网络中的最大寿命 ipechoReq.ipHeader.iaSrc.s_addr = inet_addr(sourseIP); //源主机地址 ipechoReq.ipHeader.iaDst = lpstToAddr->sin_addr; // ipechoReq.ipHeader.Protocol = IPPROTO_ICMP; //协议的类型包含ICMP ipechoReq.ipHeader.FlagOff = htons(0x2000); //第一片标志位是001000000000000 ipechoReq.ipHeader.TotLen = sizeof(IPECHOREQUET); //总产度设置成64,数据部分应该是52 ipechoReq.ipHeader.Checksum = 0; // //IP包头校验和计算 ipechoReq.ipHeader.Checksum = in_cksum((u_short *)&(ipechoReq.ipHeader),sizeof(IPHDR)); // Fill in echo request ipechoReq.icmp_data.icmpHdr.Type = ICMP_ECHOREQ; //请求数据包类型 ipechoReq.icmp_data.icmpHdr.Code = 0; // ipechoReq.icmp_data.icmpHdr.Checksum = 0; //检验和字段 ipechoReq.icmp_data.icmpHdr.ID = nId++; //成对出现的 ipechoReq.icmp_data.icmpHdr.Seq = nSeq++; //成对出现 // Save tick count when sent ipechoReq.icmp_data.dwTime = GetTickCount(); printf("n发送的时间:%dn",ipechoReq.icmp_data.dwTime); memset(DataToSend,Renum); //ICMP头部填充//////////////////////////////////////////////////////////////////////////// int nRet; for (nRet = 0;nRet < REQ_DATASIZE;nRet++) DataToSend[nRet] = 'a'; for(nRet = REQ_DATASIZE;nRet<Renum;nRet++) DataToSend[nRet] = 'b'; //第一片需要发送的数据 for (nRet = 0;nRet < REQ_DATASIZE;nRet++) ipechoReq.icmp_data.cData[nRet] = DataToSend[nRet]; //计算校验和的部分构成 if (flag1 == 0) { tempECHREQUEST tempecho; memset(tempecho.cData,Renum); tempecho.icmpHdr = ipechoReq.icmp_data.icmpHdr; tempecho.dwTime = ipechoReq.icmp_data.dwTime; memcpy(tempecho.cData,DataToSend,Renum); // Put data in packet and compute checksum ipechoReq.icmp_data.icmpHdr.Checksum = in_cksum((u_short *)&tempecho,sizeof(tempECHREQUEST)); } if (flag1==1) { tempecho temp; memset(temp.cData,Renum+8); temp.dwTime = ipechoReq.icmp_data.dwTime; temp.icmpHdr = ipechoReq.icmp_data.icmpHdr; memcpy(temp.cData,REQ_DATASIZE); //第一片复制 memcpy(temp.cData+REQ_DATASIZE,DataToSend+REQ_DATASIZE-8,REQ_datasize2); ipechoReq.icmp_data.icmpHdr.Checksum = in_cksum((u_short *)&temp,sizeof(tempecho)); } //发送echo 请求 nRet = sendto(s,(LPSTR)&ipechoReq,sizeof(IPECHOREQUET),(LPSOCKADDR)lpstToAddr,sizeof(SOCKADDR_IN)); if (nRet == SOCKET_ERROR) ReportError("sendto()"); return nRet; } /* 发送第二片数据 */ int SendIPEchoRequestFragmentTwo(SOCKET s,LPSOCKADDR_IN lpstToAddr){ IPEchoTwo ipechoReq; //第二片的IP头部处理过程 ipechoReq.ipHeader.VIHL = 0x45; //版本是4,首部长度是5 ipechoReq.ipHeader.TOS = 0x0; //由标准组织分配 ipechoReq.ipHeader.ID = ip_id; //ip的标识(一唯) ipechoReq.ipHeader.TTL = 64; //网络中的最大寿命 ipechoReq.ipHeader.iaSrc.s_addr = inet_addr(sourseIP); //源主机地址 ipechoReq.ipHeader.iaDst = lpstToAddr->sin_addr; // ipechoReq.ipHeader.Protocol = IPPROTO_ICMP; //协议的类型包含ICMP ////////////////////////////////////////////////////////////////////////////////////// if (flag1 == 0) ipechoReq.ipHeader.FlagOff = htons(0x6); //第二片标志位是 if (flag1 == 1) ipechoReq.ipHeader.FlagOff = htons(0x5); //第二片标志位是 ipechoReq.ipHeader.TotLen = sizeof(IPEchoTwo); //总产度设置成64,数据部分应该是44 ipechoReq.ipHeader.Checksum = 0; // //IP包头校验和计算 ipechoReq.ipHeader.Checksum = in_cksum((u_short *)&(ipechoReq.ipHeader),sizeof(IPHDR)); //ICMP头部填充 int nRet; //填充其他的数据部分///////////////////////////////////////////////////////////////////////////// if (flag1 == 0){ memcpy(ipechoReq.cData,DataToSend+REQ_DATASIZE,REQ_datasize2); nRet = sendto(s,sizeof(IPEchoTwo),sizeof(SOCKADDR_IN)); } if (flag1 == 1){ IPechotwo2 ipecho; ipecho.ipHeader = ipechoReq.ipHeader; memset(ipecho.cData,REQ_datasize2+8); memcpy(ipecho.cData,REQ_datasize2+8); nRet = sendto(s,sizeof(IPechotwo2),sizeof(SOCKADDR_IN)); } //发送echo 请求 if (nRet == SOCKET_ERROR) ReportError("sendto()"); return nRet; } // RecvEchoReply() // Receive incoming data // and parse out fields DWORD RecvEchoReply(SOCKET s,LPSOCKADDR_IN lpsaFrom,u_char *pTTL) { IPECHOREPLY ipreply; int nRet; int nAddrLen = sizeof(struct sockaddr_in); // Receive the echo reply nRet = recvfrom(s,// socket (LPSTR)&ipreply,// buffer sizeof(IPECHOREPLY),// size of buffer 0,// flags (LPSOCKADDR)lpsaFrom,// From address &nAddrLen); // pointer to address len // Check return value if (nRet == SOCKET_ERROR) ReportError("recvfrom()"); // return time sent and IP TTL *pTTL = ipreply.ipHdr.TTL; return(ipreply.echoRequest.dwTime); } // What happened? void ReportError(LPCSTR pWhere) { fprintf(stderr,"n%s error: %dn",WSAGetLastError()); } // WaitForEchoReply() // Use select() to determine when // data is waiting to be read int WaitForEchoReply(SOCKET s) { struct timeval Timeout; fd_set readfds; /*fd_set结构体的定义 typedef struct fd_set{ u_int fd_count; //集合中的socket数量 SOCKET fd_array[FD_SETSIZE]; //集合中包含的Socket数组 }fd_set; */ readfds.fd_count = 1; readfds.fd_array[0] = s; Timeout.tv_sec = 5; Timeout.tv_usec = 0; return(select(1,&readfds,NULL,&Timeout)); } // // Mike Muuss' in_cksum() function // and his comments from the original // ping program // // * Author - // * Mike Muuss // * U. S. Army Ballistic Research Laboratory // * December,1983 /* * I N _ C K S U M * * Checksum routine for Internet Protocol family headers (C Version) * */ u_short in_cksum(u_short *addr,int len) { register int nleft = len; register u_short *w = addr; register u_short answer; register int sum = 0; /* * Our algorithm is simple,using a 32 bit accumulator (sum),* we add sequential 16 bit words to it,and at the end,fold * back all the carry bits from the top 16 bits into the lower * 16 bits. */ while( nleft > 1 ) { sum += *w++; nleft -= 2; } /* mop up an odd byte,if necessary */ if( nleft == 1 ) { u_short u = 0; *(u_char *)(&u) = *(u_char *)w ; sum += u; } /* * add back carry outs from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return (answer); } 以上内容由PHP站长网【52php.cn】收集整理供大家参考研究 如果以上内容对您有帮助,欢迎收藏、点赞、推荐、分享。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |