C++ 实现的Ping类的封装
Ping 使用 Internet 控制消息协议(ICMP)来测试主机之间的连接。当用户发送一个 ping 请求时,则对应的发送一个 ICMP Echo 请求消息到目标主机,并等待目标主机回复一个 ICMP Echo 回应消息。如果目标主机接收到请求并且网络连接正常,则会返回一个回应消息,表示主机之间的网络连接是正常的。如果目标主机没有收到请求消息或网络连接不正常,则不会有回应消息返回。
编译报错问题解决
在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
套接字编程时非常重要,可以防止头文件冲突,确保编译顺利进行。
Ping头文件
如下头文件代码定义了几个结构体,用于表示IP协议头、ICMP协议头和Ping的回复信息。这些结构体主要用于网络编程中,解析和构建网络数据包。
|
下面是对每个结构体成员的简要说明:
- IPHeader 结构体:
m_byVerHLen
: 4位版本号 + 4位首部长度。m_byTOS
: 服务类型。m_usTotalLen
: 总长度。m_usID
: 标识。m_usFlagFragOffset
: 3位标志 + 13位片偏移。m_byTTL
: 生存时间。m_byProtocol
: 协议类型。m_usHChecksum
: 首部检验和。m_ulSrcIP
: 源IP地址。m_ulDestIP
: 目的IP地址。
- ICMPHeader 结构体:
m_byType
: ICMP类型。m_byCode
: ICMP代码。m_usChecksum
: 检验和。m_usID
: 标识符。m_usSeq
: 序号。m_ulTimeStamp
: 时间戳(非标准ICMP头部)。
- PingReply 结构体:
m_usSeq
: 序列号。m_dwRoundTripTime
: 往返时间。m_dwBytes
: 返回长度。m_dwTTL
: TTL值。
这些结构体主要用于在网络编程中处理与IP、ICMP和Ping相关的数据包。在实际应用中,可以使用这些结构体来解析接收到的网络数据包,或者构建要发送的数据包。
类成员说明:
m_sockRaw
: 用于发送原始套接字的成员变量。m_event
: WSA 事件。m_usCurrentProcID
: 当前进程 ID。m_szICMPData
: ICMP 数据。m_bIsInitSucc
: 初始化是否成功的标志。s_usPacketSeq
: 静态变量,用于记录 ICMP 包的序列号。
类方法说明:
Ping
: 执行 Ping 操作的方法,可以传入目标 IP 地址或域名、PingReply 结构体和超时时间。PingCore
: Ping 核心方法,用于发送 ICMP 数据包,计算往返时间等。CalCheckSum
: 计算检验和的方法。GetTickCountCalibrate
: 获取时钟计时器的校准值。
MyPing实现
1. CPing 构造函数和析构函数
CPing::CPing() : m_szICMPData(NULL), m_bIsInitSucc(FALSE) |
构造函数中,首先进行 Winsock 初始化,创建原始套接字,并分配内存用于存储 ICMP 数据。如果分配内存失败,则初始化标志 m_bIsInitSucc
置为 FALSE
。析构函数负责清理 Winsock 资源和释放内存。
2. PingCore 函数
BOOL CPing::PingCore(DWORD dwDestIP, PingReply *pPingReply, DWORD dwTimeout) |
PingCore
函数是 Ping 工具的核心部分,负责构建 ICMP 报文、发送报文、接收响应报文,并进行超时处理。通过循环等待接收事件,实时检测是否有 ICMP 响应报文到达。在接收到响应后,判断响应是否符合预期条件,如果符合则填充 pPingReply
结构体,并返回 TRUE
。
3. CalCheckSum 函数
USHORT CPing::CalCheckSum(USHORT *pBuffer, int nSize) |
CalCheckSum
函数用于计算 ICMP 报文的校验和。校验和的计算采用了累加和的方法,最后对累加和进行溢出处理。计算完成后,返回取反后的校验和。
4. GetTickCountCalibrate 函数
ULONG CPing::GetTickCountCalibrate() |
GetTickCountCalibrate
函数用于获取经过调校的系统时间。通过计算系统时间相对于 Ping 工具启动时的时间差,实现对系统时间的校准。这样做是为了处理系统时间溢出的情况。
5. Ping 函数
BOOL CPing::Ping(DWORD dwDestIP, PingReply *pPingReply, DWORD dwTimeout) |
Ping
函数是对 PingCore
函数的封装,根据目标 IP 地址调用 PingCore
进行 Ping
最后的MyPing.cpp
完整实现如下所示;
|
如何使用
在主程序中直接引入头文件MyPing.h
,并在main()
函数中直接调用CPing
类即可实现探测主机是否存活。
探测主机是否存活
|
运行效果如下所示;
模拟系统Ping测试
|
运行效果如下所示;
参考资料
代码的实现来源于博客园Snser博主,此处仅用于功能收录以便于后期在项目中应用。