用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】收集整理供大家参考研究 如果以上内容对您有帮助,欢迎收藏、点赞、推荐、分享。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
