Qt:Документация 4.3.2/qt4-network

Материал из Wiki.crossplatform.ru

Перейти к: навигация, поиск
40px Внимание: Актуальная версия перевода документации находится здесь

__NOTOC__

Image:qt-logo.png

Главная · Все классы · Основные классы · Классы по группам · Модули · Функции

Image:trolltech-logo.png

[Предыдущая: Поддержка GUI баз данных в Qt 4 ] [ Начало ] [Следующая: API стилей в Qt 4 ]

Содержание

[править] Модуль работы с сетью в Qt 4

Модуль работы с сетью в Qt 4 предоставляет некоторые новые возможности, такие как поддержка интернационализованных доменных имен, улучшенная поддержка IPv6 и более удобная работа. И так как Qt 4 позволило нам нарушить совместимость с предыдущими версиями, Мы сделали более интуитивно-понятными имена классов и API для более удобного использования.

[править] Общий Обзор

По сравнению с Qt 3, модуль работы с сетью в Qt 4 предлагает следующие преимущества:

  • Классы работы с серью и API Qt 4 имеют более интуитивно-понятные имена. Например, QServerSocket был переименован в QTcpServer.
  • Полный модуль работы с сетью является реентерабельным, что дает возможность использования его из нескольких потоков.
  • Появилась возможность посылать и получать датаграммы UDP с использованием синхронных сокетов (блокируя) без использования низкоуровневых API ( QSocketDevice в Qt 3).
  • QHostAddress и QHostInfo поддерживают интернационализированные имена доменов (RFC 3492).
  • QUrl облегчен и полностью поддерживает самую последнюю спецификацию URI.
  • Теперь поддерживается широковещание UDP.

Модуль работы с сетью Qt 4 предоставляет базовые классы для использования TCP и UDP, а также высокоуровневые классы для реализации клиентской стороны протоколов HTTP и FTP.

Далее идет краткий обзор классов TCP и UDP:

  • QTcpSocket инкапсулирует сокет TCP. Данный класс является потомком QIODevice, так что вместе с ним можно использовать QTextStream и QDataStream для чтения и записи данных. Это очень удобно для создания как клиента, так и сервера.
  • QTcpServer позволяет получать информацию с некоторого порта сервера. Данный класс испускает сигнал newConnection() каждый раз, когда клиент пытается соединиться с сервером. После того, как связь установлена, вы можете общаться с клиентом, использующим QTcpSocket.
  • QUdpSocket - API для посылки и приёма датаграмм UDP.

QTcpSocket и QUdpSocketнаследуют большинство своих функциональных возможностей от QAbstractSocket. Вы также можете использовать QAbstractSocket как оболочку родной модели сокета.

По умолчанию классы сокетов работают асинхронно (т.е. без блокировки) испуская сигналы-уведомления лишь когда поступают данные или когда собеседник закрывает связь. В многопоточных приложениях или в не-GUI приложениях, вы также можете использовать блокирующие (синхронизирующие) слот функции, что позволяет составлять более простые программы, со сконцентрированной в двух функциях логикой работы с сетью вместо размазанной по множеству слотов.

QFtp и QHttp используются для реализации протоколов FTP и HTTP внутри QTcpSocket. Оба класса работают асинхронно и могут планировать (т.е. ставить в очередь) запросы.

Модуль работы в сети содержит четыре вспомогательных класса: QHostAddress, QHostInfo, QUrl и QUrlInfo. QHostAddress содержит адреса IPv4 или IPv6, QHostInfo переводит имя хоста в адрес, QUrl хранит URL, и QUrlInfo хранит информацию о ресурсе на который указывает URL, такую как размер файла и дату модификации. (Поскольку QUrl используется QTextBrowser, то он является частью библиотеки QtCore, а не QtNetwork.)

Для получения более подробной информации смотрите обзор модуля QtNetwork.

[править] Примеры кода

Все приведенные здесь отрывки кода взяты из примеров программ, расположенных в директории Qt examples/network.

[править] Клиент TCP

Первый пример показывает, как можно написать клиент TCP с использованием QTcpSocket. Клиент общается с сервером удачи, который предсказывает удачу пользователя. Здесь показано, как установить сокет:

     tcpSocket = new QTcpSocket(this);
 
     connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readFortune()));
     connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
             this, SLOT(displayError(QAbstractSocket::SocketError)));

Когда клиент делает новый запрос удачи, клиент устанавливает связь с сервером:

     tcpSocket->connectToHost(hostLineEdit->text(),
                              portLineEdit->text().toInt());

Следующий код читает данные из сокета при ответе сервера:

     QDataStream in(tcpSocket);
     in.setVersion(QDataStream::Qt_4_0);
 
     if (blockSize == 0) {
         if (tcpSocket->bytesAvailable() < (int)sizeof(quint16))
             return;
 
         in >> blockSize;
     }
 
     if (tcpSocket->bytesAvailable() < blockSize)
         return;
 
     QString nextFortune;
     in >> nextFortune;
 
     if (nextFortune == currentFortune) {
         QTimer::singleShot(0, this, SLOT(requestNewFortune()));
         return;
     }
 
     currentFortune = nextFortune;

Ответ сервера начинается с размера сообщения size (который мы сохраняем в blockSize), за size следуют байты данных. Если клиент получил не все данные, то ждет, пока сервер пришлет еще.

Альтернативный подход состоит в том, чтобы блокировать слот. Весь код тогда может быть помещен в одной функции:

         const int Timeout = 5 * 1000;
 
         QTcpSocket socket;
         socket.connectToHost(serverName, serverPort);
 
         if (!socket.waitForConnected(Timeout)) {
             emit error(socket.error(), socket.errorString());
             return;
         }
 
         while (socket.bytesAvailable() < (int)sizeof(quint16)) {
             if (!socket.waitForReadyRead(Timeout)) {
                 emit error(socket.error(), socket.errorString());
                 return;
             }
         }
 
         quint16 blockSize;
         QDataStream in(&amp;socket);
         in.setVersion(QDataStream::Qt_4_0);
         in >> blockSize;
 
         while (socket.bytesAvailable() < blockSize) {
             if (!socket.waitForReadyRead(Timeout)) {
                 emit error(socket.error(), socket.errorString());
                 return;
             }
         }
 
         QMutexLocker locker(&amp;mutex);
 
         QString fortune;
         in >> fortune;
         emit newFortune(fortune);

[править] Сервер TCP

Следующие отрывки кода иллюстрируют, как написать сервер TCP с использованием QTcpServer и QTcpSocket. Здесь показано, как запустить сервер TCP:

     tcpServer = new QTcpServer(this);
     if (!tcpServer->listen()) {
         QMessageBox::critical(this, tr("Fortune Server"),
                               tr("Unable to start the server: %1.")
                               .arg(tcpServer->errorString()));
         close();
         return;
     }
 
     connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendFortune()));

Когда клиент пытается соединиться с сервером, выполняется следующий код в слоте sendFortune():

     QByteArray block;
     QDataStream out(&amp;block, QIODevice::WriteOnly);
     out.setVersion(QDataStream::Qt_4_0);
     out << (quint16)0;
     out << fortunes.at(qrand() % fortunes.size());
     out.device()->seek(0);
     out << (quint16)(block.size() - sizeof(quint16));
 
     QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
     connect(clientConnection, SIGNAL(disconnected()),
             clientConnection, SLOT(deleteLater()));
 
     clientConnection->write(block);
     clientConnection->disconnectFromHost();

[править] Отправители и получатели UDP

Здесь показано, как передать датаграмму UDP:

     udpSocket = new QUdpSocket(this);
     QByteArray datagram = "Broadcast message " + QByteArray::number(messageNo);
     udpSocket->writeDatagram(datagram.data(), datagram.size(),
                              QHostAddress::Broadcast, 45454);

Здесь показано, как принять датаграмму UDP:

     udpSocket = new QUdpSocket(this);
     udpSocket->bind(45454);
 
     connect(udpSocket, SIGNAL(readyRead()),
             this, SLOT(processPendingDatagrams()));

Тогда в слоте processPendingDatagrams() следует написать:

     while (udpSocket->hasPendingDatagrams()) {
         QByteArray datagram;
         datagram.resize(udpSocket->pendingDatagramSize());
         udpSocket->readDatagram(datagram.data(), datagram.size());
         statusLabel->setText(tr("Received datagram: \"%1\"")
                              .arg(datagram.data()));
     }

[править] Сравнение с Qt 3

Главное различие между Qt 3 и Qt 4 в том, что был устранён самый высокий уровень абстракции - QNetworkProtocol и QUrlOperator. Данные классы были попыткой сделать невозможное (объединить FTP и HTTP под одной крышей), и неудивительно, что это не удалось. Qt 4 все еще предоставляет классы QFtp и QHttp, но только с большим количеством продуманных API-функций, которые появились в Qt 3.1.

Класс Qt 3 QSocket был переименован в QTcpSocket. Новый класс поддерживает блокировки. Также стало легче обработать закрытие соединения, чем в Qt 3, там вы должны были соединить сигналы QSocket::connectionClosed() и QSocket::delayedCloseFinished().

Класс Qt 3 QServerSocket был переименован в QTcpServer. API изменился незначительно. В то время как в Qt 3 было необходимо создание подкласса QServerSocket и переопределение чисто виртуальной функции newConnection(), QTcpServer теперь испускает сигнал newConnection(), который можно соединить со слотом.

Класс QHostInfo был перепроектирован для того, чтобы использовать функцию операционной системы getaddrinfo() вместо реализации протокола DNS. Внутри себя QHostInfoпросто создает новый поток и в нём вызывает getaddrinfo(). Это было невозможно в Qt 3 потому, что getaddrinfo() вызывает блокировку, а Qt 3 был создан без поддержки многопоточности.

Класс QSocketDevice больше не является частью открытого API Qt. Если вы привыкли использовать QSocketDevice для посылки и приема датаграмм UDP, то используйте вместо него QUdpSocket. Если вы использовали QSocketDevice потому, что он поддерживал блокировку сокетов, то используйте QTcpSocket или QUdpSocket и функции блокировки ( waitForConnected(), waitForReadyRead() и т.д.) вместо него. Если вы использовали QSocketDevice из не-GUI потока, т.к. это единственный монопоточный класс организации сети в Qt 3, то вместо него используйте QTcpSocket, QTcpServer или QUdpSocket.

Внутри Qt 4 имеет класс с именем QSocketLayer, который предоставляет кроссплатформенный низкоуровневый API для работы с сокетом. Он напоминает старый класс QSocketDevice. Если пользователи попросят, мы можем сделать его открытым в следующих релизах.

Для оказания помощи в переходе на Qt 4 библиотека Qt3Support включает в себя классы Q3Dns, Q3ServerSocket, Q3Socket и Q3SocketDevice.

[Предыдущая: Поддержка GUI баз данных в Qt 4 ] [ Начало ] [Следующая: API стилей в Qt 4 ]



Copyright © 2007 Trolltech Trademarks
Qt 4.3.2