Evgenii Legotckoi
Evgenii Legotckoi6. Oktober 2015 13:13

Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt

Ich möchte Sie nur verärgern, lieber Leser. Qt verfügt nicht über die Funktionalität, um mit dem ICMP -Protokoll zu arbeiten, und dementsprechend müssen Sie für diesen Zweck die API des Zielbetriebssystems verwenden. Dies ist jedoch nicht überraschend. Das ICMP -Protokoll ist ein Low-Level-Protokoll und erfordert die Verwendung von Raw-Sockets, die in Qt nicht implementiert sind.

Dies ist jedoch kein großes Problem, da die wichtigsten Zielplattformen über die erforderliche API verfügen, um Ping-Versendungen zu implementieren. Beispielsweise bietet Microsoft eine einfache Verwendung des ICMP -Protokolls basierend auf der IcmpSendEcho. -Funktion.

Beschreibung von IcmpSendEcho

Die Funktion IcmpSendEcho sendet IPv4-ICMP-Echoanfragen und gibt Antworten auf die Echoanfragen zurück. Der Aufruf kehrt zurück, wenn das Timeout abläuft oder der Antwortpuffer voll ist.

DWORD IcmpSendEcho(
  _In_     HANDLE                 IcmpHandle,
  _In_     IPAddr                 DestinationAddress,
  _In_     LPVOID                 RequestData,
  _In_     WORD                   RequestSize,
  _In_opt_ PIP_OPTION_INFORMATION RequestOptions,
  _Out_    LPVOID                 ReplyBuffer,
  _In_     DWORD                  ReplySize,
  _In_     DWORD                  Timeout
);

Parameter

IcmpHandle [in]
Von IcmpCreateFile zurückgegebenes öffentliches Handle.

Zieladresse [in]
Die Zieladresse der Echoanforderung ist IPv4 , angegeben als IPAddr -Struktur.

RequestData [in]
Zeiger auf einen Puffer, der die zu sendende Anfrage enthält.

RequestSize [in ]
Die Größe des Anforderungsdatenpuffers in Byte, auf den der Parameter RequestData zeigt.

RequestOptions [in, optional]
Zeiger auf die IP-Header-Option für die Anfrage, angegeben als IP_OPTION_INFORMATION -Struktur. Auf 64-Bit-Plattformen wird sie als IP_OPTION_INFORMATION32 -Struktur angegeben.

Dieser Parameter kann auf NULL gesetzt werden, wenn die IP-Header-Optionen nicht angegeben sind.

Antwortpuffer [aus]
Ein Puffer, der mehrere Antworten auf eine Echoanforderung enthält. Bei der Rückgabe enthält der Puffer ein Array der Struktur ICMP_ECHO_REPLY mit den folgenden Parametern und Daten für die Antwort. Der Puffer muss groß sein, um mindestens eine ICMP_ECHO_REPLY -Struktur sowie RequestSize -Datenbytes . zu enthalten.

Auf 64-Bit-Plattformen enthält der Puffer bei der Rückgabe ein Array von ICMP_ECHO_REPLY32 -Strukturen.

Antwortgröße [Zoll]
Gibt die Größe des Antwortpuffers in Byte an. Der Puffer muss groß genug sein, um mindestens eine ICMP_ECHO_REPLY -Struktur sowie RequestSize -Datenbytes . aufzunehmen. Auf 64-Bit-Plattformen muss der Puffer groß genug sein mindestens eine ICMP_ECHO_REPLY32 -Struktur plus RequestSize Datenbytes.

Dieser Puffer muss auch groß genug sein, um mehr als 8 Byte Daten aufzunehmen (Error Message Size ICMP ).

Zeitüberschreitung [in]
Zeitüberschreitung in Millisekunden.

Rückgabewert

Die IcmpSendEcho -Funktion gibt die Anzahl der ICMP_ECHO_REPLY - oder ICMP_ECHO_REPLY32 -Strukturen zurück, die in ReplyBuffer gespeichert sind. Der Status jeder Antwort ist in einer Struktur enthalten. Wenn der Rückgabewert 0 ist, wird die Funktion GetLastError für weitere Informationen aufgerufen.

Wenn die Funktion fehlschlägt, gibt die Verwendung der Funktion GetLastError einen Fehlercode mit den folgenden Werten zurück:

  • ERROR_INSUFFICIENT_BUFFER - Der Umfang der übertragenen Daten für den Systemaufruf ist zu klein. Wenn der ReplySize -Parameter auf einen zu kleinen ReplyBuffer -Puffer zeigt, wird ein Fehler zurückgegeben.
  • ERROR_INVALID_PARAMETER - Ein ungültiger Parameter wurde an die Funktion übergeben. Dieser Fehler tritt auf, wenn der IcmpHandle -Parameter ein ungültiges Handle enthält. Dieser Fehler kann auch zurückgegeben werden, wenn ReplySize kleiner als die Größe von ICMP_ECHO_REPLY - oder ICMP_ECHO_REPLY32 -Strukturen ist.
  • ERROR_NOT_ENOUGH_MEMORY - Nicht genügend Speicher, um den Vorgang abzuschließen.
  • ERROR_NOT_SUPPORT - Die Anfrage wird nicht unterstützt. Dieser Fehler wird zurückgegeben, wenn auf dem lokalen Computer kein IPv4-Stack vorhanden ist.
  • IP_BUF_TOO_SMALL - Die im Parameter ReplySize angegebene ReplyBuffer -Größe ist zu klein.
  • Andere – Verwenden Sie FormatMessage, , um eine Zeichenfolgennachricht über den zurückgegebenen Fehler zu erhalten.

Arbeiten mit ICMP

Die Funktion IcmpSendEcho sendet eine ICMP-Echoanforderung an die angegebene Adresse und gibt die Anzahl der empfangenen und in ReplyBuffer gespeicherten Antworten zurück. Die IcmpSendEcho -Funktion ist eine synchrone Funktion und kehrt zurück, nachdem die Antwort abgelaufen ist. Wenn Null zurückgegeben wird, muss die Funktion GetLastError aufgerufen werden, um erweiterte Informationen zu erhalten.

Um diesen Teil der WinAPI zu verwenden, müssen Sie die folgenden zwei Zeilen in die .Pro-Projektdatei schreiben:

LIBS     += -lws2_32
LIBS     += -liphlpapi

Und schließen Sie auch die folgenden Bibliotheken ein:

#include "winsock2.h"
#include "iphlpapi.h"
#include "icmpapi.h"

Hauptanwendungsfenster

Um sich mit dem ICMP-Protokoll vertraut zu machen, erstellen wir ein Fenster mit der folgenden Oberfläche, in der die Antwort auf Anfragen, die IP-Adresse und der Start-Button angezeigt werden.

Widget.h

Neben der Deklaration des Slots über die Schaltfläche sehen Sie hier nichts Interessantes, aber ich gebe trotzdem die Header-Datei an.

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QDebug>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

Widget.cpp

Und hier ist das Interessanteste. Durch Drücken der Schaltfläche Wir pingen die von uns gewählte IP-Adresse an. Für die Schönheit der Lösung habe ich die Validierung der IP-Adresse in das Feld lintEdit eingegeben.

#include "widget.h"
#include "ui_widget.h"
#include "winsock2.h"
#include "iphlpapi.h"
#include "icmpapi.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    // Производим валидацию вводимых данных IP-адреса
    QString ipRange = "(?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])";

    QRegExp ipRegex ("^" + ipRange
                     + "\\." + ipRange
                     + "\\." + ipRange
                     + "\\." + ipRange + "$");

    QRegExpValidator *ipValidator = new QRegExpValidator(ipRegex, this);
    ui->lineEdit->setValidator(ipValidator);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    // Объявляем переменные
    HANDLE hIcmpFile;                       // Обработчик
    unsigned long ipaddr = INADDR_NONE;     // Адрес назначения
    DWORD dwRetVal = 0;                     // Количество ответов
    char SendData[32] = "Data Buffer";      // Буффер отсылаемых данных
    LPVOID ReplyBuffer = NULL;              // Буффер ответов
    DWORD ReplySize = 0;                    // Размер буффера ответов

    // Устанавливаем IP-адрес из поля lineEdit
    ipaddr = inet_addr(ui->lineEdit->text().toStdString().c_str());
    hIcmpFile = IcmpCreateFile();   // Создаём обработчик

    // Выделяем память под буффер ответов
    ReplySize = sizeof(ICMP_ECHO_REPLY) + sizeof(SendData);
    ReplyBuffer = (VOID*) malloc(ReplySize);

    // Вызываем функцию ICMP эхо запроса
    dwRetVal = IcmpSendEcho(hIcmpFile, ipaddr, SendData, sizeof(SendData),
                NULL, ReplyBuffer, ReplySize, 1000);

    // создаём строку, в которою запишем сообщения ответа
    QString strMessage = "";

    if (dwRetVal != 0) {
        // Структура эхо ответа
        PICMP_ECHO_REPLY pEchoReply = (PICMP_ECHO_REPLY)ReplyBuffer;
        struct in_addr ReplyAddr;
        ReplyAddr.S_un.S_addr = pEchoReply->Address;

        strMessage += "Sent icmp message to " + ui->lineEdit->text() + "\n";
        if (dwRetVal > 1) {
            strMessage += "Received " + QString::number(dwRetVal) + " icmp message responses \n";
            strMessage += "Information from the first response: ";
        }
        else {
            strMessage += "Received " + QString::number(dwRetVal) + " icmp message response \n";
            strMessage += "Information from the first response: ";
        }
            strMessage += "Received from ";
            strMessage += inet_ntoa( ReplyAddr );
            strMessage += "\n";
            strMessage += "Status = " + pEchoReply->Status;
            strMessage += "Roundtrip time = " + QString::number(pEchoReply->RoundTripTime) + " milliseconds \n";
    } else {
        strMessage += "Call to IcmpSendEcho failed.\n";
        strMessage += "IcmpSendEcho returned error: ";
        strMessage += QString::number(GetLastError());
    }

    ui->textEdit->setText(strMessage); // Отображаем информацию о полученных данных
    free(ReplyBuffer); // Освобождаем память
}

Insgesamt

Als Ergebnis sollten Sie eine Anwendung haben, die die IP-Adresse Ihrer Wahl pingt.

Eine Demonstration der Anwendung wird im Video-Tutorial gegeben.

Videoanleitung

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

АК
  • 5. Februar 2024 01:50
  • (bearbeitet)

Без строки

#include <QRegularExpressionValidator>

в заголовочном файле не работает валидатор.

Kommentare

Nur autorisierte Benutzer können Kommentare posten.
Bitte Anmelden oder Registrieren
Letzte Kommentare
ИМ
Игорь Максимов5. Oktober 2024 13:51
Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55. Juli 2024 17:02
QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssr9. Februar 2024 00:43
Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25. Dezember 2023 16:30
Boost - statisches Verknüpfen im CMake-Projekt unter Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
Jetzt im Forum diskutieren
J
JacobFib17. Oktober 2024 09:27
добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
JW
Jhon Wick1. Oktober 2024 21:52
Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
КГ
Кирилл Гусарев27. September 2024 15:09
Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
F
Fynjy22. Juli 2024 10:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Folgen Sie uns in sozialen Netzwerken