文章目录
- 目的
- 关于ICMP
- socket 编程实现ICMP
- 编译error
- 代码
- 参考博客
- 扩展了解
目的
通过C++编程实现ping, 也算是对于SOCKET编程初步了解掌握。
- 了解ICMP协议
- 了解对应socket编程
关于ICMP
请参考我的博客Ping工作原理
socket 编程实现ICMP
Ping 使用 Internet 控制消息协议(ICMP)来测试主机之间的连通性。当用客户端发送一个 ping 请求时,则对应的发送一个 ICMP Echo 请求消息到目标主机,并等待目标主机回复一个 ICMP Echo 回应消息。如果目标主机接收到请求并且网络连接正常,则会返回一个回应消息,表示主机之间的网络连接是正常的。如果目标主机没有收到请求消息或网络连接不正常,则不会有回应消息返回。
编译error
-
winsock2.h 与 windows.h 先后顺序导致编译错误
在Windows环境下编程不可避免的会用到windows.h和winsock.h头文件,在默认情况下windows.h头文件会包含winsock.h,此时当尝试包含winsock.h时就会出现头文件定义冲突的情况。解决这个冲突的方式有两种,第一种,在头部定义#define WIN32_LEAN_AND_MEAN来主动去除winsock.h头文件包含。第二种是将#include <winsock2.h>头文件,放在#include<windows.h>之前。两种方式均可,这些方法在进行Windows套接字编程时非常重要,可以防止头文件冲突,确保编译顺利进行。 -
IPExport.h导致编译错误
还有一种是我遇到的 OptionsData 未知重写说明符, Data 未知重写说明符
需要将如下注释掉就行, 具体原因后续有时间整理下。
//#include <iphlpapi.h>
//#include <icmpapi.h>
代码
- ICMPDataHeader.h
相关头文件声明 与 数据定义
#pragma once#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <vector>
#include <cmath>
#include <chrono>
#include <ctime>
//#include <iphlpapi.h>
//#include <icmpapi.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>#pragma comment(lib, "ws2_32.lib")
//#pragma comment(lib, "iphlpapi.lib")#define IP_RECORD_ROUTE 0x7// IP header structure
typedef struct _iphdr
{//Suppose the BYTE_ORDER is LITTLE_ENDIANunsigned int h_len:4; // Length of the headerunsigned int version:4; // Version of IPunsigned char tos; // Type of serviceunsigned short total_len; // Total length of the packetunsigned short id; // Unique identificationunsigned short frag_offset; // Fragment offsetunsigned char ttl; // Time to liveunsigned char protocol; // Protocol (TCP, UDP etc)unsigned short checksum; // IP checksumunsigned int sourceIP; // Source IPunsigned int destIP; // Destination IP
} IpHeader;#define ICMP_ECHO 8
#define ICMP_ECHOREPLY 0
#define ICMP_MIN 8 // Minimum 8-byte ICMP packet (header)// ICMP header structure
// This is not the standard header, but we reserve space for time
typedef struct _icmphdr
{BYTE i_type;BYTE i_code; // Type sub codeUSHORT i_cksum;USHORT i_id;USHORT i_seq;ULONG timestamp;
} IcmpHeader;// IP option header - use with socket option IP_OPTIONS
typedef struct _ipoptionhdr
{unsigned char code; // Option typeunsigned char len; // Length of option hdrunsigned char ptr; // Offset into optionsunsigned long addr[9]; // List of IP addrs
} IpOptionHeader;#define DEF_PACKET_SIZE 32 // Default packet size
#define MAX_PACKET 1024 // Max ICMP packet size
#define MAX_IP_HDR_SIZE 60 // Max IP header size w/options
- 关键核心代码 cpp
校验函数
#include "icmppacketprocessor.h"ICMPPacketProcessor::ICMPPacketProcessor(QObject* parent):QObject{parent}
{}ICMPPacketProcessor::~ICMPPacketProcessor()
{if(lpdest){delete lpdest;}
}unsigned short ICMPPacketProcessor::checksum(unsigned short *buffer, int size)
{unsigned long cksum=0;while(size > 1){cksum += *buffer++;size -= sizeof(unsigned short);}if(size){cksum += *(UCHAR*)buffer;}cksum = (cksum >> 16) + (cksum & 0xffff);cksum += (cksum >>16);return (unsigned short)(~cksum);
}// Function: FillICMPData
// Description:
// Helper function to fill in various fields for our ICMP request
void ICMPPacketProcessor::fillICMPData(char *icmp_data, int datasize)
{IcmpHeader *icmp_hdr = NULL;char *datapart = NULL;icmp_hdr = (IcmpHeader*)icmp_data;icmp_hdr->i_type = ICMP_ECHO; // Request an ICMP echo, type is 8icmp_hdr->i_code = 0; // code is 0icmp_hdr->i_id = (USHORT)GetCurrentProcessId();icmp_hdr->i_cksum = 0;icmp_hdr->i_seq = 0;datapart = icmp_data + sizeof(IcmpHeader);// Place some junk in the buffermemset(datapart, 'E' , datasize - sizeof(IcmpHeader));
}
// Function: DecodeIPOptions
// Description:
// If the IP option header is present, find the IP options
// within the IP header and print the record route option values
void ICMPPacketProcessor::decodeIPOptions(char *buf, int bytes)
{IpOptionHeader *ipopt = NULL;IN_ADDR inaddr;int i;HOSTENT *host = NULL;ipopt = (IpOptionHeader *)(buf + 20);printf("Record Route: ");for(i = 0; i < (ipopt->ptr / 4) - 1; i++){inaddr.S_un.S_addr = ipopt->addr[i];if (i != 0) printf(" ");host = gethostbyaddr(