Программирование сетей с Qt
Модуль сетей Qt предоставляет классы, позволяющие создавать TCP/IP-клиенты и серверы. Он предлагает классы низкого уровня, такие как QTcpSocket, QTcpServer и QUdpSocket, представляющие низкоуровневые сетевые концепции, и классы высокого уровня, такие как QNetworkRequest, QNetworkReply и QNetworkAccessManager, для выполнения сетевых операций с использованием стандартных протоколов. Он также предоставляет такие классы, как QNetworkConfiguration, QNetworkConfigurationManager и QNetworkSession, которые реализуют управление подключением.
Классы Qt для программирования сетей
Страница классов Qt Network C++ содержит список C++-классов в Qt Network.
Высокоуровневые сетевые операции для HTTP и FTP
API доступа к сетям — это набор классов для выполнения общих сетевых операций. API предоставляет абстрактный уровень над конкретными операциями и протоколами (например, получение и отправка данных по HTTP) и предоставляет только классы, функции и сигналы для общих или высокоуровневых концепций.
Сеть запросы представлены классом QNetworkRequest, который также служит общим контейнером для информации, связанной с запросом, например, любой заголовком и используемым шифрованием. URL, указанный при создании объекта запроса, определяет протокол, используемый для запроса. В настоящее время поддерживаются URL HTTP, FTP и локальных файлов для загрузки и скачивания.
Координацию сетевых операций выполняет класс QNetworkAccessManager. После создания запроса этот класс используется для его отправки и генерации сигналов для отчёта о его ходе. Менеджер также координирует использование cookies для хранения данных на клиенте, запросов аутентификации и использования прокси.
Ответы на сетевые запросы представлены классом QNetworkReply; они создаются QNetworkAccessManager при отправке запроса. Сигналы, предоставляемые QNetworkReply, могут использоваться для отслеживания каждого ответа индивидуально, или разработчики могут использовать сигналы менеджера для этой цели вместо этого и отбросить ссылки на ответы. Поскольку QNetworkReply является подклассом QIODevice, ответы могут обрабатываться синхронно или асинхронно; т. е. как блокирующие или неблокирующие операции.
Каждое приложение или библиотека может создавать один или несколько экземпляров QNetworkAccessManager для обработки сетевого взаимодействия.
Использование TCP с QTcpSocket и QTcpServer
TCP (Transmission Control Protocol) — это низкоуровневый сетевой протокол, используемый большинством интернет-протоколов, включая HTTP и FTP, для передачи данных. Это надёжный, потоковый, ориентированный на соединение транспортный протокол. Он особенно подходит для непрерывной передачи данных.
Класс QTcpSocket предоставляет интерфейс для TCP. Вы можете использовать QTcpSocket для реализации стандартных сетевых протоколов, таких как POP3, SMTP и NNTP, а также пользовательских протоколов.
Соединение TCP должно быть установлено с удалённым хостом и портом перед началом любой передачи данных. После установления соединения IP-адрес и порт удалённого узла доступны через QTcpSocket::peerAddress() и QTcpSocket::peerPort(). В любой момент удалённый узел может закрыть соединение, и передача данных немедленно прекратится.
QTcpSocket работает асинхронно и генерирует сигналы для отчёта о статусе изменений и ошибках, как и QNetworkAccessManager. Он полагается на цикл событий для обнаружения входящих данных и автоматического вывода исходящих данных. Вы можете записывать данные в сокет с помощью QTcpSocket::write() и читать данные с помощью QTcpSocket::read(). QTcpSocket представляет два независимых потока данных: один для чтения и один для записи.
Поскольку QTcpSocket наследует QIODevice, вы можете использовать его с QTextStream и QDataStream. При чтении из QTcpSocket необходимо убедиться, что доступны достаточные данные, вызвав QTcpSocket::bytesAvailable() предварительно.
Если вам нужно обрабатывать входящие TCP-соединения (например, в приложении сервера), используйте класс QTcpServer. Вызовите QTcpServer::listen() для настройки сервера и подключитесь к сигналу QTcpServer::newConnection(), который генерируется один раз для каждого подключаемого клиента. В вашем слоте вызовите QTcpServer::nextPendingConnection() для принятия соединения и используйте возвращаемый QTcpSocket для связи с клиентом.
Хотя большинство его функций работают асинхронно, использование QTcpSocket синхронно (т. е. блокировка) возможно. Для получения блокирующего поведения вызовите функции waitFor...() QTcpSocket; они приостанавливают вызывающую нить до тех пор, пока не будет сгенерирован сигнал. Например, после вызова неблокирующей функции QTcpSocket::connectToHost() вызовите QTcpSocket::waitForConnected(), чтобы заблокировать нить до тех пор, пока не будет сгенерирован сигнал connected().
Синхронные сокеты часто приводят к коду с более простым потоком управления. Основным недостатком подхода waitFor...() является то, что события не будут обрабатываться, пока функция waitFor...() заблокирована. Если она используется в потоке GUI, это может заблокировать пользовательский интерфейс приложения. По этой причине мы рекомендуем использовать синхронные сокеты только в не-GUI-потоках. При синхронном использовании QTcpSocket не требует цикла событий.
Примеры Fortune Client и Fortune Server демонстрируют, как использовать QTcpSocket и QTcpServer для создания TCP-клиент-серверных приложений. См. также Blocking Fortune Client для примера использования синхронного QTcpSocket в отдельном потоке (без использования цикла событий) и Threaded Fortune Server для примера многопоточного TCP-сервера с одним потоком на активного клиента.
Использование UDP с QUdpSocket
UDP (User Datagram Protocol) — это лёгкий, ненадежный, ориентированный на дейтаграммы, бессоединительный протокол. Он может использоваться, когда надёжность не имеет значения. Например, сервер, который сообщает время суток, может выбрать UDP. Если дейтаграмма с временем суток потеряна, клиент может просто сделать другой запрос.
Класс QUdpSocket позволяет отправлять и получать UDP-дейтаграммы. Он наследует QAbstractSocket и, следовательно, разделяет большую часть интерфейса QTcpSocket. Основное различие заключается в том, что QUdpSocket передает данные как дейтаграммы, а не как непрерывный поток данных. Короче говоря, дейтаграмма — это пакет данных ограниченного размера (обычно меньше 512 байт), содержащий IP-адрес и порт отправителя и получателя дейтаграммы, а также данные, передаваемые.
QUdpSocket поддерживает IPv4-вещание. Вещание часто используется для реализации протоколов обнаружения сети, таких как поиск узла в сети с наибольшим свободным объёмом жёсткого диска. Один узел транслирует дейтаграмму в сеть, которую принимают все остальные узлы. Каждый узел, который получает запрос, отправляет ответ отправителю со своим текущим объёмом свободного места на диске. Инициатор ждёт, пока не получит ответы от всех узлов, и может выбрать сервер с наибольшим свободным местом для хранения данных. Чтобы отправить дейтаграмму на вещание, просто отправьте её по специальному адресу QHostAddress::Broadcast (255.255.255.255) или по адресу вещания вашей локальной сети.
QUdpSocket::bind() подготавливает сокет к приёму входящих дейтаграмм, подобно QTcpServer::listen() для TCP-серверов. Всякий раз, когда поступает одна или несколько дейтаграмм, QUdpSocket генерирует сигнал readyRead(). Вызовите QUdpSocket::readDatagram() для чтения дейтаграммы.
Примеры Broadcast Sender и Broadcast Receiver показывают, как создать UDP-отправителя и UDP-получателя с помощью Qt.
QUdpSocket также поддерживает мультикастинг. Примеры Multicast Sender и Multicast Receiver демонстрируют, как использовать UDP-мультикаст-клиенты.
Разрешение имён хостов с помощью QHostInfo
Перед установлением сетевого соединения QTcpSocket и QUdpSocket выполняют поиск имени, преобразуя имя хоста, к которому вы подключаетесь, в IP-адрес. Обычно эта операция выполняется с помощью протокола DNS (Domain Name Service).
QHostInfo предоставляет статическую функцию, которая позволяет вам выполнить такой поиск самостоятельно. Вызвав QHostInfo::lookupHost() с именем хоста, указателем QObject и сигнатурой слота, QHostInfo выполнит поиск имени и вызовет заданный слот, когда результаты будут готовы. Фактический поиск выполняется в отдельном потоке, используя собственные методы операционной системы для выполнения поиска имен.
QHostInfo также предоставляет статическую функцию QHostInfo::fromName(), которая принимает имя хоста в качестве аргумента и возвращает результаты. В этом случае поиск имени выполняется в том же потоке, что и вызывающий поток. Эта перегрузка полезна для приложений, не использующих GUI, или для выполнения поиска имен в отдельном, не-GUI-потоке. (Вызов этой функции в потоке GUI может привести к зависанию вашего пользовательского интерфейса, пока функция блокируется во время выполнения поиска.)
Поддержка сетевых прокси
Сеть взаимодействие с Qt может выполняться через прокси, которые направляют или фильтруют сетевой трафик между локальными и удаленными подключениями.
Индивидуальные прокси представлены классом QNetworkProxy, который используется для описания и настройки подключения к прокси. Поддерживаются типы прокси, работающие на разных уровнях сетевого взаимодействия, при этом поддержка SOCKS 5 позволяет проксировать сетевой трафик на низком уровне, а HTTP и FTP проксирование работает на уровне протокола. Дополнительную информацию см. в QNetworkProxy::ProxyType.
Проксирование может быть включено на основе каждого сокета или для всех сетевых взаимодействий в приложении. Новый сокет может быть настроен для использования прокси путем вызова функции QAbstractSocket::setProxy() перед его подключением. Включение проксирования для всех последующих подключений сокетов по всему приложению может быть выполнено с помощью функции QNetworkProxy::setApplicationProxy().
Прокси-фабрики используются для создания политик использования прокси. QNetworkProxyFactory предоставляет прокси на основе запросов для конкретных типов прокси. Сами запросы закодированы в объектах QNetworkProxyQuery, которые позволяют выбирать прокси на основе ключевых критериев, таких как назначение прокси (TCP, UDP, TCP-сервер, запрос URL), локальный порт, удаленный хост и порт, а также используемый протокол (HTTP, FTP и т. д.).
QNetworkProxyFactory::proxyForQuery() используется для непосредственного запроса фабрики. Политику проксирования по всему приложению можно реализовать, передав фабрику в QNetworkProxyFactory::setApplicationProxyFactory(), а пользовательскую политику проксирования можно создать, создав подкласс QNetworkProxyFactory; подробности см. в документации класса.
Поддержка управления каналом
Управление каналом контролирует состояние подключения устройства таким образом, что приложение может запускать или останавливать сетевые интерфейсы и прозрачно перемещаться между точками доступа.
Класс QNetworkConfigurationManager управляет списком сетевых конфигураций, известных устройству. Сетевая конфигурация описывает набор параметров, используемых для запуска сетевого интерфейса, и представлена классом QNetworkConfiguration.
Сетевой интерфейс запускается путем открытия QNetworkSession на основе заданной сетевой конфигурации. В большинстве случаев предпочтительно создание сетевого сеанса на основе платформенной стандартной сетевой конфигурации. Стандартная сетевая конфигурация возвращается функцией QNetworkConfigurationManager::defaultConfiguration().
На некоторых платформах требуется, чтобы приложение открыло сетевой сеанс перед выполнением любых сетевых операций. Это можно проверить по наличию флага QNetworkConfigurationManager::NetworkSessionRequired в значении, возвращаемом функцией QNetworkConfigurationManager::capabilities().
См. также Управление каналом.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.9/qtnetwork-programming.html