Программирование сетей с помощью Qt
Модуль Qt Network предоставляет классы, позволяющие создавать TCP/IP-клиенты и серверы. Он предлагает низкоуровневые классы, такие как QTcpSocket, QTcpServer и QUdpSocket, представляющие низкоуровневые сетевые концепции, и высокоуровневые классы, такие как QNetworkRequest, QNetworkReply и QNetworkAccessManager, для выполнения сетевых операций с использованием общих протоколов.
Классы Qt для программирования сетей
Страница C++ классы Qt Network содержит список C++ классов в Qt Network.
Высокоуровневые сетевые операции для HTTP
API доступа к сети — это набор классов для выполнения общих сетевых операций. API предоставляет абстракционный слой над конкретными операциями и протоколами (например, получение и отправка данных по HTTP), и экспонирует только классы, функции и сигналы для общих или высокоуровневых концепций.
Сеть запросы представлены классом QNetworkRequest, который также служит контейнером для информации, связанной с запросом, такой как заголовки и используемое шифрование. URL, указанный при создании объекта запроса, определяет используемый протокол. В настоящее время поддерживаются URL HTTP и локальных файлов для загрузки и скачивания.
Координация сетевых операций выполняется классом 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; см. документацию класса для получения подробностей.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.2/qtnetwork-programming.html