代码
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
#include "winsock2.h"
#include "string.h"
#pragma comment(lib,"WS2_32")
#define DATALEN 1012
#define PACKAGENUM 10
using namespace std;
typedef struct icmp_hdr {
unsigned char icmp_type; //icmp包类型
unsigned char icmp_code; //代码
unsigned short icmp_checksum; //校验和
unsigned short icmp_id; //标识
unsigned short icmp_sequence; //序列号
unsigned long icmp_timestamp; //时间戳
} IcmpHeader;
unsigned short checksum(unsigned short *buff, int size);
int main(int argc, char **argv) {
WSADATA wsaData;
int ret;
if ((ret = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) {
cout << "初始化WinSock2.2出错!";
return -1;
}
char szDestIp[256] = { 0 };
/*
if (argc < 2) {
cout << "\n用法:ping IP 地址|域名\n";
return -1;
}
strcpy(szDestIp, argv[1]); //从命令行读取ip地址或域名
*/
cout << "请输入目的地址:" << endl;
cin.getline(szDestIp, sizeof(szDestIp));
//解析域名
unsigned long ulDestIP = inet_addr(szDestIp);
if (ulDestIP == INADDR_NONE) {
hostent* pHostent = gethostbyname(szDestIp);
if (pHostent != NULL) {
ulDestIP = (*(in_addr*)pHostent->h_addr).s_addr;
}
else {
cout << "无法解析主机名" << endl;
WSACleanup();
return -1;
}
/*
char **pptr;
pptr = pHostent->h_addr_list;
while (*pptr != NULL) {
cout << inet_ntoa(*(struct in_addr *)(*pptr)) << endl; pptr++;
}*/
}
SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); //收发icmp包的原始套接字
int nTime = 1000;
ret = setsockopt(sRaw, SOL_SOCKET, SO_RCVTIMEO, (char *)&nTime, sizeof(nTime));
if (ret == SOCKET_ERROR) {
cout << "套接字选项设置出错" << endl;
return -1;
}
SOCKADDR_IN dest;
dest.sin_family = AF_INET;
dest.sin_port = htons(0);
dest.sin_addr.S_un.S_addr = ulDestIP;
char buff[sizeof(IcmpHeader) + DATALEN];
IcmpHeader *pIcmp = (IcmpHeader *)buff;
pIcmp->icmp_type = 8;
pIcmp->icmp_code = 0;
pIcmp->icmp_id = (unsigned short)GetCurrentProcessId();
pIcmp->icmp_timestamp = 0;
pIcmp->icmp_checksum = 0;
pIcmp->icmp_sequence = 0;
memset(&buff[sizeof(IcmpHeader)], 'A', DATALEN); //填充数据部分
if (connect(sRaw, (SOCKADDR *)&dest, sizeof(dest))!=0){
cout << "连接失败!" << endl;
closesocket(sRaw);
WSACleanup();
return -1;
}
int nRet, n = 0;
bool bTimeout;
unsigned short nSeq = 0; //发送的ICMP报文的序号
char recvBuf[32 + DATALEN];
SOCKADDR_IN from;
int nLen = sizeof(from);
static int nCount = 0;
IcmpHeader *pRecvIcmp;
pRecvIcmp = NULL;
while (TRUE) {
//cout << nCount << endl;
if (nCount++ == PACKAGENUM)break;
pIcmp->icmp_checksum = 0;
pIcmp->icmp_timestamp = GetTickCount();
pIcmp->icmp_sequence = nSeq++;
pIcmp->icmp_checksum = checksum((unsigned short*)buff, sizeof(IcmpHeader) + DATALEN);
//cout << buff[5] << endl;
nRet = send(sRaw, buff, sizeof(IcmpHeader) + DATALEN, 0);
if (nRet == SOCKET_ERROR) {
cout << "发送失败!" <<WSAGetLastError()<< endl;
closesocket(sRaw);
WSACleanup();
return -1;
}
bTimeout = false;n = 0;
do {
n++;
memset((void *)recvBuf, 0, sizeof(recvBuf));
nRet = recvfrom(sRaw, recvBuf, sizeof(recvBuf), 0, (sockaddr *)&from, &nLen);
if (nRet == SOCKET_ERROR) {
if (WSAGetLastError() == WSAETIMEDOUT) {
cout << "time out!" << endl;
bTimeout = true;
break;
}
cout << "接收应答包失败!" << endl;
return -1;
}
pRecvIcmp = (IcmpHeader *)(recvBuf + 20); //收到的数据包含20个字节的IP首部,加20是ICMP首部位置
if (pRecvIcmp->icmp_id != GetCurrentProcessId()) {
cout << "unexpected message" << endl;
}
else break;
} while (n < 10);
if (n > 10) {
cout << "too many icmps!" << endl;
closesocket(sRaw);
WSACleanup();
return -1;
}
if (bTimeout)continue;
int nTick = GetTickCount();
if (nRet < 20 + sizeof(IcmpHeader)) {
cout << "too feww bytes from " << inet_ntoa(from.sin_addr) << endl;
continue;
}
else {
cout << nRet << " bytes from:" << inet_ntoa(from.sin_addr);
cout << "icmp_seq = " << pRecvIcmp->icmp_sequence;
cout << " time:" << nTick - pRecvIcmp->icmp_timestamp << " ms" << endl;
Sleep(1000);
}
}
closesocket(sRaw);
WSACleanup();
return 0;
}
unsigned short checksum(unsigned short * buff, int size) {
unsigned long cksum = 0;
while (size > 1) {
cksum += *buff++;
size -= sizeof(unsigned short);
}
if (size)cksum += *(char *)buff;
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
return (unsigned short)(~cksum);
}
结果