Fortune Client ExampleFiles: The Fortune Client example shows how to create a client for a simple network service using QTcpSocket. It is intended to be run alongside the Fortune Server example or the Threaded Fortune Server example. This example uses a simple QDataStream-based data transfer protocol to request a line of text from a fortune server (from the Fortune Server example). The client requests a fortune by simply connecting to the server. The server then responds with a 16-bit (quint16) integer containing the length of the fortune text, followed by a QString. QTcpSocket supports two general approaches to network programming:
In this example, we will demonstrate the asynchronous approach. The Blocking Fortune Client example illustrates the synchronous approach. Our class contains some data and a few private slots: class Client : public QDialog { Q_OBJECT public: Client(QWidget *parent = 0); private slots: void requestNewFortune(); void readFortune(); void displayError(QAbstractSocket::SocketError socketError); void enableGetFortuneButton(); private: QLabel *hostLabel; QLabel *portLabel; QLineEdit *hostLineEdit; QLineEdit *portLineEdit; QLabel *statusLabel; QPushButton *getFortuneButton; QPushButton *quitButton; QTcpSocket *tcpSocket; QString currentFortune; quint16 blockSize; }; Other than the widgets that make up the GUI, the data members include a QTcpSocket pointer, a copy of the fortune text currently displayed, and the size of the packet we are currently reading (more on this later). The socket is initialized in the Client constructor. We'll pass the main widget as parent, so that we won't have to worry about deleting the socket: Client::Client(QWidget *parent) : QDialog(parent) { ... tcpSocket = new QTcpSocket(this); The only QTcpSocket signals we need in this example are QTcpSocket::readyRead(), signifying that data has been received, and QTcpSocket::error(), which we will use to catch any connection errors: ... connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readFortune())); connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError))); ... } Clicking the Get Fortune button will invoke the requestNewFortune() slot: void Client::requestNewFortune() { getFortuneButton->setEnabled(false); blockSize = 0; tcpSocket->abort(); tcpSocket->connectToHost(hostLineEdit->text(), portLineEdit->text().toInt()); } In this slot, we initialize blockSize to 0, preparing to read a new block of data. Because we allow the user to click Get Fortune before the previous connection finished closing, we start off by aborting the previous connection by calling QTcpSocket::abort(). (On an unconnected socket, this function does nothing.) We then proceed to connecting to the fortune server by calling QTcpSocket::connectToHost(), passing the hostname and port from the user interface as arguments. As a result of calling connectToHost(), one of two things can happen:
Let's go through the error() case first: void Client::displayError(QAbstractSocket::SocketError socketError) { switch (socketError) { case QAbstractSocket::RemoteHostClosedError: break; case QAbstractSocket::HostNotFoundError: QMessageBox::information(this, tr("Fortune Client"), tr("The host was not found. Please check the " "host name and port settings.")); break; case QAbstractSocket::ConnectionRefusedError: QMessageBox::information(this, tr("Fortune Client"), tr("The connection was refused by the peer. " "Make sure the fortune server is running, " "and check that the host name and port " "settings are correct.")); break; default: QMessageBox::information(this, tr("Fortune Client"), tr("The following error occurred: %1.") .arg(tcpSocket->errorString())); } getFortuneButton->setEnabled(true); } We pop up all errors in a dialog using QMessageBox::information(). QTcpSocket::RemoteHostClosedError is silently ignored, because the fortune server protocol ends with the server closing the connection. Now for the readyRead() alternative. This signal is connected to Client::readFortune(): void Client::readFortune() { 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; The protocol is based on QDataStream, so we start by creating a stream object, passing the socket to QDataStream's constructor. We then explicitly set the protocol version of the stream to QDataStream::Qt_4_0 to ensure that we're using the same version as the fortune server, no matter which version of Qt the client and server use. Now, TCP is based on sending a stream of data, so we cannot expect to get the entire fortune in one go. Especially on a slow network, the data can be received in several small fragments. QTcpSocket buffers up all incoming data and emits readyRead() for every new block that arrives, and it is our job to ensure that we have received all the data we need before we start parsing. The server's response starts with the size of the packet, so first we need to ensure that we can read the size, then we will wait until QTcpSocket has received the full packet. QString nextFortune; in >> nextFortune; if (nextFortune == currentFortune) { QTimer::singleShot(0, this, SLOT(requestNewFortune())); return; } currentFortune = nextFortune; statusLabel->setText(currentFortune); getFortuneButton->setEnabled(true); } We proceed by using QDataStream's streaming operator to read the fortune from the socket into a QString. Once read, we can call QLabel::setText() to display the fortune. See also Fortune Server Example and Blocking Fortune Client Example. |
Publicité
Best OfActualités les plus luesSemaine
Mois
Année
Le Qt Labs au hasardPeek et PokeLes Qt Labs sont les laboratoires des développeurs de Qt, où ils peuvent partager des impressions sur le framework, son utilisation, ce que pourrait être son futur. Lire l'article.
CommunautéRessources
Liens utilesContact
Qt dans le magazine |
Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. | Qt 4.1 | |
Copyright © 2012 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD. | ||
Vous avez déniché une erreur ? Un bug ? Une redirection cassée ? Ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP ! |
Copyright © 2000-2012 - www.developpez.com