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.
Без строки
в заголовочном файле не работает валидатор.