Модуль работы с сетью в Qt 4Модуль работы с сетью в Qt 4 предоставляет некоторые новые возможности, такие как поддержка интернационализированных доменных имен, улучшенная поддержка IPv6 и более удобная работа. И так как Qt 4 позволило нам нарушить совместимость с предыдущими версиями, мы сделали более интуитивно понятными имена классов и API для более удобного использования. Общий обзорПо сравнению с Qt 3, модуль работы с сетью в Qt 4 предлагает следующие преимущества:
Модуль работы с сетью Qt 4 предоставляет базовые классы для использования TCP и UDP, а также высокоуровневые классы для реализации клиентской стороны протоколов HTTP и FTP. Далее идет краткий обзор классов TCP и UDP:
QTcpSocket и QUdpSocket наследуют большинство своих функциональных возможностей от QAbstractSocket. Вы также можете использовать QAbstractSocket как оболочку родной модели сокета. По умолчанию классы сокетов работают асинхронно (т.е. без блокировки) испуская сигналы-уведомления лишь когда поступают данные или когда собеседник закрывает связь. В многопоточных приложениях или в не-GUI приложениях, вы также можете использовать блокирующие (синхронизирующие) слот функции, что позволяет составлять более простые программы, со сконцентрированной в двух функциях логикой работы с сетью вместо размазанной по множеству слотов. QFtp и QNetworkAccessManager и их связанные классы используют QTcpSocket для внутренних нужд чтобы реализовать протоколы FTP и HTTP. Классы работают асинхронно и могут планировать (т.е. ставить в очередь) запросы. Модуль работы в сети содержит четыре вспомогательных класса: 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(&socket); in.setVersion(QDataStream::Qt_4_0); in >> blockSize; while (socket.bytesAvailable() < blockSize) { if (!socket.waitForReadyRead(Timeout)) { emit error(socket.error(), socket.errorString()); return; } } mutex.lock(); 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(&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, QUdpSocket::ShareAddress); 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, а также он предоставляет QNetworkAccessManager. Класс 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. |
Попытка перевода Qt документации. Если есть желание присоединиться, или если есть замечания или пожелания, то заходите на форум: Перевод Qt документации на русский язык... Люди внесшие вклад в перевод: Команда переводчиков |