QT 在Windows下实现ping功能(ICMP)

前言

很多时候,我们可能会图省事直接调用系统中的ping命令,但这是很不科学的~

废话不多说,直接上代码..

.pro文件

在.pro文件末尾添加一行:

复制代码
LIBS += -liphlpapi -lws2_32

.h文件

在.h文件中加入:

复制代码
#include <QDebug>
#include <winsock2.h>
#include <iphlpapi.h>
#include <icmpapi.h>
#include <ws2tcpip.h>
#include <iostream>
using namespace std;

private:
    int ping(const char *ip); #也可以加在public下,不是一定要private

.cpp文件:

cpp 复制代码
// ping函数
int Widget::ping(const char *ip){
    //通常使用MAKEWORD宏来指定版本,如MAKEWORD(2, 2)表示使用Winsock 2.2版本。
    WSADATA wsaData;

    //WSAStartup函数用于初始化Winsock库,并指定Winsock库的版本。这个函数需要在使用Winsock库的其他函数之前调用,而在程序结束时,你需要调用WSACleanup函数来释放Winsock库的资源。
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        qDebug()<<"Error1:"<<WSAGetLastError();
        return -1;
    }

    // 创建socket
    SOCKET sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sock == INVALID_SOCKET)
    {
        qDebug()<<"Error2:"<<WSAGetLastError();
        return -2;
    }

    //设置目的地址
    SOCKADDR_IN dest;
    dest.sin_family = AF_INET;
    dest.sin_addr.s_addr = inet_addr(ip);

    //创建ICMP数据包
    const int packet_size = 32; //数据包大小,取值范围 0-65507
    char packet[packet_size];
    memset(packet, 0, packet_size); //memset函数通常用于初始化一段内存空间,或者将一段内存空间清空。这句的作用是将packet指向的内存空间清空,以便后续的代码可以使用这段内存空间来存储ICMP报文

    //创建icmp句柄
    ICMP_ECHO_REPLY reply;
    HANDLE icmp_handle = IcmpCreateFile();
    if (icmp_handle == INVALID_HANDLE_VALUE)
    {
        qDebug()<<"Error3:"<<GetLastError();
        return -3;
    }

    DWORD reply_size = packet_size + 28; //接收到的ICMP回复数据的大小。+28等同于:+sizeof(reply)

    //发送ICMP数据包
    int status = IcmpSendEcho(icmp_handle, dest.sin_addr.s_addr, packet, packet_size, NULL, &reply, reply_size, 2000);

    if (status == 0) //这里status == 0 表示执行失败,要查看错误码可以查看: reply.Status
    {
        qDebug()<<"Error4:"<<GetLastError();
        return -4;
    }

    // Print the response
    qDebug()<<"延时:" << reply.RoundTripTime; //查看延时
    qDebug()<<"包大小:" << reply.DataSize; //查看数据包大小
    qDebug()<<"TTL值:" << (int)reply.Options.Ttl; //查看ttl值

    WSACleanup(); //释放WSAStartup

    return reply.RoundTripTime; //返回延时
}

ping函数调用方法示例:

方法一:

cpp 复制代码
ping("192.168.1.1");

方法二:

cpp 复制代码
QString ip = "192.168.1.1";
ping(ip.toUtf8());

如果要重复执行,可以通过循环重复调用ping函数..

reply.Status状态码:

|--------------------------|-----------|---------------------------|
| 常量名 | | 含义 |
| IP_SUCCESS | 0 | 状态是成功。 |
| IP_BUF_TOO_SMALL | 11001 | 答复缓冲区太小。 |
| IP_DEST_NET_UNREACHABLE | 11002 | 目标网络不可达。 |
| IP_DEST_HOST_UNREACHABLE | 11003 | 目标主机不可达。 |
| IP_DEST_PROT_UNREACHABLE | 11004 | 目的地的协议是遥不可及。 |
| IP_DEST_PORT_UNREACHABLE | 11005 | 目标端口不可达。 |
| IP_NO_RESOURCES | 11006 | IP资源不足。 |
| IP_BAD_OPTION | 11007 | 指定了错误的IP选项。 |
| IP_HW_ERROR | 11008 | 一个硬件错误。 |
| IP_PACKET_TOO_BIG | 11009 | 包太大。 |
| IP_REQ_TIMED_OUT | 11010 | 请求超时。 |
| IP_BAD_REQ | 11011 | 一个坏的请求。 |
| IP_BAD_ROUTE | 11012 | 一个糟糕的路线。 |
| IP_TTL_EXPIRED_TRANSIT | 11013 | 在传输过程中的生存时间(TTL)的过期。 |
| IP_TTL_EXPIRED_REASSEM | 11014 | 在碎片重组过程中的生存时间过期。 |
| IP_PARAM_PROBLEM | 11015 | 一个参数的问题。 |
| IP_SOURCE_QUENCH | 11016 | 数据报到达太快,处理和数据报可能被丢弃。 |
| IP_OPTION_TOO_BIG | 11017 | 一个IP选项是太大了。 |
| IP_BAD_DESTINATION | 11018 | 一个坏的目的地。 |
| IP_GENERAL_FAILURE | 11050 | 一般故障。这个错误可以返回一些畸形的ICMP数据包 |

相关推荐
望获linux2 小时前
【Linux基础知识系列】第一百一十篇 - 使用Nmap进行网络安全扫描
java·linux·开发语言·前端·数据库·信息可视化·php
雷达学弱狗5 小时前
链式法则解释上游梯度应用
开发语言·前端·javascript
小清兔8 小时前
c#基础知识
开发语言·数据库·学习·unity·c#·游戏引擎·.net
奇某人9 小时前
【语法】【C+V】本身常用图表类型用法快查【CSDN不支持,VSCODE可用】
开发语言·vscode·markdown·mermaid
做一位快乐的码农10 小时前
php程序设计之基于PHP的手工艺品销售网站/基于php在线销售系统/基于php在线购物商城系统
开发语言·php
@珍惜一生@10 小时前
Qt开源库
开发语言·qt·开源
Slaughter信仰11 小时前
深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)第四章知识点问答补充及重新排版
java·开发语言·jvm
心灵宝贝11 小时前
Mac用户安装JDK 22完整流程(Intel版dmg文件安装指南附安装包下载)
java·开发语言·macos
secondyoung11 小时前
一文丝滑使用Markdown:从写作、绘图到转换为Word与PPT
开发语言·vscode·编辑器·powerpoint·markdown·visual studio·mermaid
Univin11 小时前
8.25作业
数据结构·windows