#include<iostream>
#include<string.h>
#include<WinSock2.h>
#include<thread>
#include<ws2def.h>
#include<ws2ipdef.h>
#pragma comment(lib,"ws2_32.lib")
// ICMP 报文头
struct icmpHeader {
unsigned char type; // 类型
unsigned char code; // 代码
unsigned short checkSum; // 检验和
unsigned short id; // 标识符
unsigned short sequence; // 序列号
};
// 计算检验
unsigned short computeCks(icmpHeader* picmp, int len) {
long sum = 0;
unsigned short* pusicmp = (unsigned short*)picmp;
while (len > 1) {
sum += *(pusicmp++);
if (sum & 0x80000000)
sum = (sum & 0xffff) + (sum >> 16);
len -= 2;
}
if (len)
sum += (unsigned short)*(unsigned char*)pusicmp;
while (sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
return (unsigned short)~sum;
}
int ping(const std::string& targetIP) {
// 初始化套接字库
WORD wReq = MAKEWORD(2, 2);
WSADATA wsadata;
WSAStartup(wReq, &wsadata);
// 填充服务端地址
SOCKADDR_IN6 serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin6_family = AF_INET6;
serverAddr.sin6_addr = inet_addr(targetIP.c_str());
SOCKET s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMP);
// 构造 ICMP 报文
char sendBuf[8 + 32] = { 0 };
icmpHeader* pIcmp = (icmpHeader*)sendBuf;
pIcmp->type = 8;
pIcmp->code = 0;
pIcmp->checkSum = 0;
pIcmp->id = (USHORT)::GetCurrentProcessId();
pIcmp->sequence = 0;
// 填充数据部分
memcpy(sendBuf + 8, "abcdelmnopqrstuvwiammekakuactor", 32);
// 计算检验和
pIcmp->checkSum = computeCks((icmpHeader*)sendBuf, sizeof(sendBuf));
// 发送报文
DWORD start = GetTickCount64();
int sendLen = sendto(s, sendBuf, sizeof(sendBuf), 0, (SOCKADDR*)&serverAddr, sizeof(SOCKADDR));
if (sendLen < 0) printf("errno = %d\n", GetLastError());
// 接收报文
char recvBuf[1024];
SOCKADDR_IN6 fromAddr;
int fLen = sizeof(fromAddr);
unsigned timeOut = 1000; // 超时时间
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeOut, sizeof(timeOut)); // 设置接收超时
while (true) {
int len = recvfrom(s, recvBuf, 1024, 0, (SOCKADDR*)&fromAddr, &fLen);
if (len < 0) {
std::cout << "请求超时" << std::endl;
return INT32_MAX;
}
else break;
}
DWORD end = GetTickCount64();
DWORD timeSpan = end - start;
// 回送报文解析
char ipInfo = recvBuf[0];
// ipv4 头部的第 9 个字节为 TTL 的值
//ipv6 头部的第55个字段为TTL的值
unsigned char ttl = recvBuf[54];
int ipHeadLen = ((char)(ipInfo << 4) >> 4) * 4; // IP报文头部长度
icmpHeader* icmpResp = (icmpHeader*)(recvBuf + ipHeadLen);
if (icmpResp->type == 0) { //回显应答报文
printf("来自 %s 的回复:字节=32 时间=%2dms TTL=%d\n",
targetIP.c_str(), timeSpan, ttl);
return timeSpan;
}
else {
printf("请求超时。type = %d\n", icmpResp->type);
return INT32_MAX;
}
}
int main() {
std::cout << "请输入目的IP地址:";
std::string IP;
std::cin >> IP;
int maxTime = INT32_MIN, minTime = INT32_MAX, timeSum = 0, acpkgCnt = 0;
printf("\n正在 Ping %s 具有 32 字节的数据:\n", IP.c_str());
while (1) {
std::this_thread::sleep_for(std::chrono::seconds(1));
int timeSpan = ping(IP);
acpkgCnt += timeSpan != INT32_MAX;
maxTime = max(maxTime, timeSpan);
minTime = min(minTime, timeSpan);
timeSum += timeSpan;
}
printf("\n%s 的 Ping 统计信息:\n", IP.c_str());
printf(" 数据包: 已发送 = 4,已接收 = %d,丢失 = %d (%d%% 丢失),\n",
acpkgCnt, 4 - acpkgCnt, (4 - acpkgCnt) * 100 / 4);
if (!acpkgCnt) return 0;
printf("往返行程的估计时间(以毫秒为单位):\n");
printf(" 最短 = %dms,最长 = %dms,平均 = %dms\n", minTime, maxTime, timeSum / acpkgCnt);
}
serverAddr.sin6_addr = inet_addr(targetIP.c_str());
这块报错,其实到这里我也不知道怎么去改。ipv4是可以的 但是ipv6不行。希望指点一下
错误(活动) E0349 没有与这些操作数匹配的 "=" 运算符
错误 C2679 二元“=”: 没有找到接受“unsigned long”类型的右操作数的运算符(或没有可接受的转换)
sin6_addr 是个结构体。 inet_addr的返回值是runsigned long