Evgenii Legotckoi
Evgenii LegotckoiҚаз. 6, 2015, 1:13 Т.Қ.

Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу

Сходу хочу расстроить Вас, Дорогой Читатель. Qt не обладает функционалом для работы с протоколом ICMP и соответственно придется использовать для этих целей API целевой операционной системы. Впрочем, это не удивительно. Протокол ICMP является низкоуровневым протоколом, и для работы с ним требуется использование сырых сокетов, которые не реализованы в Qt .

Но это не является особой проблемой, поскольку в основных целевых платформах имеется необходимый API для реализации ping посылок. Например Microsoft предоставляет простое использование ICMP протокола на основе функции IcmpSendEcho.

Описание IcmpSendEcho

Функция IcmpSendEcho отсылает эхо запросы IPv4 ICMP и возвращает ответы на эхо запросы. Вызов возвращается когда выходит время ожидания или заполняется буфер ответа.

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
);

Параметры

IcmpHandle [in]
Открытый обработчик, возвращаемый функцией IcmpCreateFile .

DestinationAddress [in]
Адрес назначения эхо запроса IPv4 , задаётся в виде IPAddr структуры.

RequestData [in]
Указатель на буффер, который содержит посылаемый запрос.

RequestSize [in ]
Размер, в байтах, буффера данных запроса, на который указывает параметр RequestData .

RequestOptions [in, optional]
Указатель на опции IP заголовка для запроса, задаётся в виде IP_OPTION_INFORMATION структуры. На 64-битных платформах задаётся в виде IP_OPTION_INFORMATION32 структуры.

Этот параметр может иметь значение NULL , если опции IP заголовка не уточняются.

ReplyBuffer [out]
Буфер, удерживающий нескольку ответов на эхо запрос. По возвращении, буффер содержит массив структуры ICMP_ECHO_REPLY следующих параметров и данных для ответа. Буффер должен быть большим, для того чтобы содержать по меньшей мере одну ICMP_ECHO_REPLY структуру, а также RequestSize байтов данных .

На 64-битных платформах по возвращении буффер содержит массив ICMP_ECHO_REPLY32 структуры.

ReplySize [in]
Указывает размер, в байтах, для буффера ответа. Буффер должен быть большим, для того чтобы содержать по меньшей мере одну ICMP_ECHO_REPLY структуру, а также RequestSize байтов данных . на 64-битных платформах буффер должен быть достаточно большим, чтобы содержать по меньшей мере одну ICMP_ECHO_REPLY32 структуру и плюс RequestSize байтов данных.

Это буффер должен быть также большим для удержания более 8 байтов данных (Размер сообщения ошибки ICMP ).

Timeout [in]
Время ожидания в миллисекундах.

Возвращаемое значение

Функция IcmpSendEcho возвращает число ICMP_ECHO_REPLY или ICMP_ECHO_REPLY32 структур, сохранённых в ReplyBuffer . Статус каждого ответа содержится в структуре. Если возвращаемое значение равно 0, вызывается функция GetLastError для дополнительной информации.

Если функция терпит неудачу, то с помощью функции GetLastError возвратит код ошибки со следующими значениями:

  • ERROR_INSUFFICIENT_BUFFER - Область передаваемых данных для системного вызова слишком мала. Ошибка возвращается, если параметр ReplySize указывает на буффер ReplyBuffer, который слишком мал.
  • ERROR_INVALID_PARAMETER - Неверный параметр был передан в функцию. Эта ошибка возникает в том случае, если параметр IcmpHandle содержит ошибочный обработчик. Эта ошибка может быть возвращена также, если параметр ReplySize имеет значение меньшее чем размер ICMP_ECHO_REPLY или ICMP_ECHO_REPLY32 структур.
  • ERROR_NOT_ENOUGH_MEMORY - Недостаточно памяти для завершения операции.
  • ERROR_NOT_SUPPORT - Запрос не поддерживается. Эта ошибка возвращается, если нет стека IPv4 на локальном компьютере.
  • IP_BUF_TOO_SMALL - Размер ReplyBuffer, указанный в параметре ReplySize является слишком малым.
  • Другие - Используйте FormatMessage, для того чтобы получить строковое сообщение о возвращаемой ошибке.

Работа с ICMP

Функция IcmpSendEcho посылает ICMP эхо запрос по указанному адресу и возвращает число пинятых и сохранённых ответов в ReplyBuffer . Функция IcmpSendEcho является синхронной функцией и возвращает значение после окончания времени ожидания для ответа. Если возвращается ноль, то для получения расширенной информации необходимо вызвать функцию GetLastError .

Для того, чтобы использовать данную часть WinAPI, необходимо в .Pro файле проекта прописать две следующих строки:

LIBS     += -lws2_32
LIBS     += -liphlpapi

А также подключить следующие библиотеки:

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

Главное окно приложения

Для того, чтобы ознакомиться с протоколом ICMP создадим окно со следующим интерфейсом, где будет отображаться ответ на запросы, IP-адрес и кнопка запуска.

widget.h

Кроме объявления слота от кнопки Вы здесь ничего интересного не увидите, но тем не менее привожу заголовочный файл.

#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

А вот здесь самое интересное. По нажатию кнопки Мы будем пинговать выбранный нами IP-адрес. Для красоты решения я ввёл валидацию IP-адреса в поле lintEdit.

#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); // Освобождаем память
}

Итог

В результате у Вас должно получиться приложение, которое будет пинговать выбранный Вами IP-адрес.

Демонстрация работы приложения приведена в видеоуроке.

Видеоурок

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

АК
  • Ақп. 5, 2024, 1:50 Т.Ж.
  • (өңделген)

Без строки

#include <QRegularExpressionValidator>

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

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
OI
  • Ora Iro
  • Жел. 24, 2024, 6:38 Т.Ж.

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:40ұпай,
  • Бағалау ұпайлары-8
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:50ұпай,
  • Бағалау ұпайлары-4
m
  • molni99
  • Қаз. 26, 2024, 1:37 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:80ұпай,
  • Бағалау ұпайлары4
Соңғы пікірлер
ИМ
Игорь МаксимовҚар. 22, 2024, 11:51 Т.Ж.
Django - Оқулық 017. Теңшелген Django кіру беті Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii LegotckoiҚаз. 31, 2024, 2:37 Т.Қ.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEҚаз. 19, 2024, 8:19 Т.Ж.
Qt Creator көмегімен fb3 файл оқу құралы Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовҚаз. 5, 2024, 7:51 Т.Ж.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Қар. 15, 2024, 6:04 Т.Ж.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectМаусым 4, 2022, 3:49 Т.Ж.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9AnonimҚаз. 25, 2024, 9:10 Т.Ж.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Бізді әлеуметтік желілерде бақылаңыз