2 Star 1 Fork 0

Reviel / ICMP协议的Ping和TraceRouter

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
Ping.cpp 4.74 KB
一键复制 编辑 原始数据 按行查看 历史
Reviel 提交于 2018-07-09 14:33 . 最开始的把两个文件放入git系统
#include <winsock2.h>
#include <iostream>
#include <windows.h>
#include <tchar.h>
using namespace std;
#define DATA_SIZE 32
#define RECV_MAX_SIZE 1024
#pragma comment(lib, "ws2_32.lib")//该库对应ws2_32.dll,提供了一些网络相关API的支持
typedef struct tag_icmphdr //icmp头,长8字节
{
unsigned char icmp_type; //ICMP类型,只用8号和0号数据报,回送请求和回送回答报文
unsigned char icmp_code; //ICMP代码
unsigned short icmp_checksum; //ICMP校验和
unsigned short icmp_id; //ICMP标识符
unsigned short icmp_sequence; //ICMP序列号
unsigned long icmp_timestamp; //ICMP时间戳
} ICMPHDR, *PICMPHDR;
typedef struct tag_iphdr //ip头,长20字节
{
UCHAR iphVerLen;
UCHAR ipTOS;
USHORT ipLength;
USHORT ipID;
USHORT ipFlags;
UCHAR ipTTL;
UCHAR ipProtacol;
USHORT ipChecksum;
ULONG ipSource;
ULONG ipDestination;
} IPHDR;
USHORT CheckSum(USHORT *buf, int size)//计算校验和
{
USHORT cksum = 0;
while (size>1)
{
cksum += *buf++;
size -= sizeof(USHORT);
}
if (size)
cksum += *buf++;
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
return (USHORT)(~cksum);
}
void FillIcmp(PICMPHDR p) //ICMP报文填充
{
p->icmp_type = 8; //ICMP报文类型8,不同类型结构不同
p->icmp_code = 0;
p->icmp_checksum = 0;
p->icmp_id = (unsigned short)::GetCurrentProcessId();//按进程号处理
p->icmp_sequence = 0;
p->icmp_timestamp = 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
//初始化套接字环境
WORD version = MAKEWORD(2, 2);
WSADATA data;
WSAStartup(version, &data);
if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2)
{
cout << "WSAStartup failed" << endl;
WSACleanup();//关闭环境
return 0;
}
char ip[20]; //IP地址
cout << "ping: ";
cin >> ip;
SOCKADDR_IN addr; //目标主机地址,仅使用IP地址,不含域名解析
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = inet_addr(ip);
addr.sin_port = htons(0);
SOCKET sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); //创建原始套接字(缺少错误处理)
int outTime = 3000; //超时时间,设为3秒
int rst;
rst = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&outTime, sizeof(int)); //设置发送时限
if (SOCKET_ERROR == rst)
{
cout << "setsockopt error" << endl;
closesocket(sock);
WSACleanup();
return -1;
}
rst = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&outTime, sizeof(int)); //设置接收时限
if (SOCKET_ERROR == rst)
{
cout << "setsockopt error" << endl;
closesocket(sock);
WSACleanup();
return -1;
}
char *icmp = (char*)malloc(sizeof(ICMPHDR) + DATA_SIZE); //为icmp包申请内存
memset(icmp, 0, sizeof(ICMPHDR) + DATA_SIZE); //内存空间置零
PICMPHDR picmp = (PICMPHDR)icmp;
FillIcmp(picmp); //填充icmp包
unsigned short sequence = 0; //序列号
int count = 4; //发送请求次数,一般4次
char recvbuf[RECV_MAX_SIZE]; //创建接收缓冲区,最大1024字节
SOCKADDR_IN addrfrom; //接收地址
int len = sizeof(SOCKADDR); //地址大小
int ipTTL = 0; //TTL
while (count--)
{//每次请求中:
picmp->icmp_checksum = 0;
picmp->icmp_timestamp = ::GetTickCount(); //获取当前时间作为时间戳
picmp->icmp_sequence = sequence++;
picmp->icmp_checksum = CheckSum((USHORT*)icmp, sizeof(ICMPHDR) + DATA_SIZE);
int result;
result = sendto(sock, icmp, sizeof(ICMPHDR) + DATA_SIZE, 0, (SOCKADDR*)&addr, sizeof(SOCKADDR));//向目标主机发送icmp请求包
if (SOCKET_ERROR == result)
{
if (WSAETIMEDOUT == WSAGetLastError())
{
cout << "time out" << endl;
continue;
}
else
{
cout << "sendto error" << endl;
closesocket(sock);
WSACleanup();
return -1;
}
}
result = recvfrom(sock, recvbuf, RECV_MAX_SIZE, 0, (SOCKADDR*)&addrfrom, &len);//接收目标主机的icmp应答包
if (SOCKET_ERROR == result)
{
if (WSAETIMEDOUT == GetLastError())
{
cout << "time out" << endl;
continue;
}
else
{
cout << "recvform error" << endl;
closesocket(sock);
WSACleanup();
return -1;
}
}
int nTick = ::GetTickCount();//当前时间
if (result < sizeof(IPHDR) + sizeof(ICMPHDR) + DATA_SIZE)
{//检验收到包的大小
cout << "too few bytes" << endl;
}
IPHDR *pIP = (IPHDR*)recvbuf;//缓冲区内容强制类型转换成hdr,可直接使用(一个解码过程)
ipTTL = (int)pIP->ipTTL; //获取目标主机TTL
PICMPHDR p = (PICMPHDR)(recvbuf + sizeof(IPHDR));//指针p从IP头移动到ICMP头
if (p->icmp_type != 0)
{//收到错误类型的包
cout << "error type " << p->icmp_type << " receved" << endl;
return -1;
}
if (p->icmp_id != (USHORT)::GetCurrentProcessId())
{//得到的包id错误
cout << "someone else's packet" << endl;
return -1;
}
cout << "reply from: " << inet_ntoa(addrfrom.sin_addr);
cout << " data: " << DATA_SIZE << "bytes "; //IP长8字节,ICMP长20字节,数据长32字节,共应60字节
cout << " time: " << nTick - p->icmp_timestamp << "ms"; //传输时间=当前时间-ICMP产生时的时间
cout << " TTL=" << ipTTL << endl;
}
system("pause");
return 0;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/reviel/ICMP_Ping_TraceRouter.git
git@gitee.com:reviel/ICMP_Ping_TraceRouter.git
reviel
ICMP_Ping_TraceRouter
ICMP协议的Ping和TraceRouter
master

搜索帮助

344bd9b3 5694891 D2dac590 5694891