Программирование сетей с Qt
Модуль Qt Network предоставляет классы, которые позволяют создавать TCP/IP-клиенты и серверы. Он предлагает классы низкого уровня, такие как QTcpSocket, QTcpServer и QUdpSocket, которые представляют концепции сетей низкого уровня, а также классы высокого уровня, такие как QNetworkRequest, QNetworkReply и QNetworkAccessManager, для выполнения сетевых операций с использованием общих протоколов. Он также предлагает классы, такие как QNetworkConfiguration, QNetworkConfigurationManager и QNetworkSession, которые реализуют управление носителем.
Классы Qt для программирования сетей
Страница классов C++ Qt Network содержит список классов 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 с помощью 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/archives/qt-5.11/qtnetwork-programming.html