qt 6.5.1 original
BIN
examples/network/doc/images/blockingfortuneclient-example.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
examples/network/doc/images/broadcastreceiver-example.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
examples/network/doc/images/broadcastsender-example.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
examples/network/doc/images/fortuneclient-example.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
examples/network/doc/images/fortuneserver-example.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
examples/network/doc/images/http-example.webp
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
examples/network/doc/images/multicastreceiver-example.webp
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
examples/network/doc/images/multicastsender-example.webp
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
examples/network/doc/images/network-chat-example.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
examples/network/doc/images/securesocketclient.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
examples/network/doc/images/securesocketclient2.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
examples/network/doc/images/secureudpclient-example.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
examples/network/doc/images/secureudpserver-example.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
examples/network/doc/images/threadedfortuneserver-example.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
examples/network/doc/images/torrent-example.png
Normal file
After Width: | Height: | Size: 18 KiB |
175
examples/network/doc/src/blockingfortuneclient.qdoc
Normal file
@ -0,0 +1,175 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example blockingfortuneclient
|
||||
\title Blocking Fortune Client
|
||||
\examplecategory {Networking}
|
||||
\meta tags {tcp,network,threading,synchronous-io}
|
||||
\ingroup examples-network
|
||||
\brief Demonstrates how to create a client for a network service.
|
||||
|
||||
\image blockingfortuneclient-example.png
|
||||
|
||||
QTcpSocket supports two general approaches to network programming:
|
||||
|
||||
\list
|
||||
|
||||
\li \e{The asynchronous (non-blocking) approach.} Operations are scheduled
|
||||
and performed when control returns to Qt's event loop. When the operation
|
||||
is finished, QTcpSocket emits a signal. For example,
|
||||
QTcpSocket::connectToHost() returns immediately, and when the connection
|
||||
has been established, QTcpSocket emits
|
||||
\l{QTcpSocket::connected()}{connected()}.
|
||||
|
||||
\li \e{The synchronous (blocking) approach.} In non-GUI and multithreaded
|
||||
applications, you can call the \c waitFor...() functions (e.g.,
|
||||
QTcpSocket::waitForConnected()) to suspend the calling thread until the
|
||||
operation has completed, instead of connecting to signals.
|
||||
|
||||
\endlist
|
||||
|
||||
The implementation is very similar to the
|
||||
\l{fortuneclient}{Fortune Client} example, but instead of having
|
||||
QTcpSocket as a member of the main class, doing asynchronous networking in
|
||||
the main thread, we will do all network operations in a separate thread
|
||||
and use QTcpSocket's blocking API.
|
||||
|
||||
The purpose of this example is to demonstrate a pattern that you can use
|
||||
to simplify your networking code, without losing responsiveness in your
|
||||
user interface. Use of Qt's blocking network API often leads to
|
||||
simpler code, but because of its blocking behavior, it should only be used
|
||||
in non-GUI threads to prevent the user interface from freezing. But
|
||||
contrary to what many think, using threads with QThread does not
|
||||
necessarily add unmanagable complexity to your application.
|
||||
|
||||
We will start with the FortuneThread class, which handles the network
|
||||
code.
|
||||
|
||||
\snippet blockingfortuneclient/fortunethread.h 0
|
||||
|
||||
FortuneThread is a QThread subclass that provides an API for scheduling
|
||||
requests for fortunes, and it has signals for delivering fortunes and
|
||||
reporting errors. You can call requestNewFortune() to request a new
|
||||
fortune, and the result is delivered by the newFortune() signal. If any
|
||||
error occurs, the error() signal is emitted.
|
||||
|
||||
It's important to notice that requestNewFortune() is called from the main,
|
||||
GUI thread, but the host name and port values it stores will be accessed
|
||||
from FortuneThread's thread. Because we will be reading and writing
|
||||
FortuneThread's data members from different threads concurrently, we use
|
||||
QMutex to synchronize access.
|
||||
|
||||
\snippet blockingfortuneclient/fortunethread.cpp 2
|
||||
|
||||
The requestNewFortune() function stores the host name and port of the
|
||||
fortune server as member data, and we lock the mutex with QMutexLocker to
|
||||
protect this data. We then start the thread, unless it is already
|
||||
running. We will come back to the QWaitCondition::wakeOne() call later.
|
||||
|
||||
\snippet blockingfortuneclient/fortunethread.cpp 4
|
||||
\snippet blockingfortuneclient/fortunethread.cpp 5
|
||||
|
||||
In the run() function, we start by acquiring the mutex lock, fetching the
|
||||
host name and port from the member data, and then releasing the lock
|
||||
again. The case that we are protecting ourselves against is that \c
|
||||
requestNewFortune() could be called at the same time as we are fetching
|
||||
this data. QString is \l reentrant but \e not \l{thread-safe}, and we must
|
||||
also avoid the unlikely risk of reading the host name from one request,
|
||||
and port of another. And as you might have guessed, FortuneThread can only
|
||||
handle one request at a time.
|
||||
|
||||
The run() function now enters a loop:
|
||||
|
||||
\snippet blockingfortuneclient/fortunethread.cpp 6
|
||||
|
||||
The loop will continue requesting fortunes for as long as \e quit is
|
||||
false. We start our first request by creating a QTcpSocket on the stack,
|
||||
and then we call \l{QTcpSocket::connectToHost()}{connectToHost()}. This
|
||||
starts an asynchronous operation which, after control returns to Qt's
|
||||
event loop, will cause QTcpSocket to emit
|
||||
\l{QTcpSocket::connected()}{connected()} or
|
||||
\l{QTcpSocket::error()}{error()}.
|
||||
|
||||
\snippet blockingfortuneclient/fortunethread.cpp 8
|
||||
|
||||
But since we are running in a non-GUI thread, we do not have to worry
|
||||
about blocking the user interface. So instead of entering an event loop,
|
||||
we simply call QTcpSocket::waitForConnected(). This function will wait,
|
||||
blocking the calling thread, until QTcpSocket emits connected() or an
|
||||
error occurs. If connected() is emitted, the function returns true; if the
|
||||
connection failed or timed out (which in this example happens after 5
|
||||
seconds), false is returned. QTcpSocket::waitForConnected(), like the
|
||||
other \c waitFor...() functions, is part of QTcpSocket's \e{blocking
|
||||
API}.
|
||||
|
||||
After this statement, we have a connected socket to work with.
|
||||
|
||||
\snippet blockingfortuneclient/fortunethread.cpp 11
|
||||
|
||||
Now we can create a QDataStream object, passing the socket to
|
||||
QDataStream's constructor, and as in the other client examples we set
|
||||
the stream protocol version to QDataStream::Qt_4_0.
|
||||
|
||||
\snippet blockingfortuneclient/fortunethread.cpp 12
|
||||
|
||||
We proceed by initiating a loop that waits for the fortune string data by
|
||||
calling QTcpSocket::waitForReadyRead(). If it returns false, we abort the
|
||||
operation. After this statement, we start a stream read transaction. We
|
||||
exit the loop when QDataStream::commitTransaction() returns true, which
|
||||
means successful fortune string loading. The resulting fortune is
|
||||
delivered by emitting newFortune():
|
||||
|
||||
\snippet blockingfortuneclient/fortunethread.cpp 15
|
||||
|
||||
The final part of our loop is that we acquire the mutex so that we can
|
||||
safely read from our member data. We then let the thread go to sleep by
|
||||
calling QWaitCondition::wait(). At this point, we can go back to
|
||||
requestNewFortune() and look closely at the call to wakeOne():
|
||||
|
||||
\snippet blockingfortuneclient/fortunethread.cpp 1
|
||||
\dots
|
||||
\snippet blockingfortuneclient/fortunethread.cpp 3
|
||||
|
||||
What happened here was that because the thread falls asleep waiting for a
|
||||
new request, we needed to wake it up again when a new request
|
||||
arrives. QWaitCondition is often used in threads to signal a wakeup call
|
||||
like this.
|
||||
|
||||
\snippet blockingfortuneclient/fortunethread.cpp 0
|
||||
|
||||
Finishing off the FortuneThread walkthrough, this is the destructor that
|
||||
sets \e quit to true, wakes up the thread and waits for the thread to exit
|
||||
before returning. This lets the \c while loop in run() will finish its current
|
||||
iteration. When run() returns, the thread will terminate and be destroyed.
|
||||
|
||||
Now for the BlockingClient class:
|
||||
|
||||
\snippet blockingfortuneclient/blockingclient.h 0
|
||||
|
||||
BlockingClient is very similar to the Client class in the
|
||||
\l{fortuneclient}{Fortune Client} example, but in this class
|
||||
we store a FortuneThread member instead of a pointer to a QTcpSocket.
|
||||
When the user clicks the "Get Fortune" button, the same slot is called,
|
||||
but its implementation is slightly different:
|
||||
|
||||
\snippet blockingfortuneclient/blockingclient.cpp 0
|
||||
|
||||
We connect our FortuneThread's two signals newFortune() and error() (which
|
||||
are somewhat similar to QTcpSocket::readyRead() and QTcpSocket::error() in
|
||||
the previous example) to requestNewFortune() and displayError().
|
||||
|
||||
\snippet blockingfortuneclient/blockingclient.cpp 1
|
||||
|
||||
The requestNewFortune() slot calls FortuneThread::requestNewFortune(),
|
||||
which \e schedules the request. When the thread has received a new fortune
|
||||
and emits newFortune(), our showFortune() slot is called:
|
||||
|
||||
\snippet blockingfortuneclient/blockingclient.cpp 2
|
||||
\codeline
|
||||
\snippet blockingfortuneclient/blockingclient.cpp 3
|
||||
|
||||
Here, we simply display the fortune we received as the argument.
|
||||
|
||||
\sa {Fortune Client}, {Fortune Server}
|
||||
*/
|
14
examples/network/doc/src/broadcastreceiver.qdoc
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example broadcastreceiver
|
||||
\title Broadcast Receiver Example
|
||||
\ingroup examples-network
|
||||
\brief Demonstrates how to receive information broadcasted over a local network.
|
||||
|
||||
This example uses the Qt Network APIs to demonstrate how to receive
|
||||
messages broadcasted over a local network.
|
||||
|
||||
\image broadcastreceiver-example.png
|
||||
*/
|
14
examples/network/doc/src/broadcastsender.qdoc
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example broadcastsender
|
||||
\title Broadcast Sender Example
|
||||
\ingroup examples-network
|
||||
\brief Demonstrates how to broadcast information to multiple clients on a local network.
|
||||
|
||||
This example uses Qt Network APIs to demonstrate how to broadcast messages
|
||||
to multiple clients over a local network.
|
||||
|
||||
\image broadcastsender-example.png
|
||||
*/
|
138
examples/network/doc/src/fortuneclient.qdoc
Normal file
@ -0,0 +1,138 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example fortuneclient
|
||||
\title Fortune Client
|
||||
\examplecategory {Networking}
|
||||
\meta tags {tcp,network}
|
||||
\ingroup examples-network
|
||||
\brief Demonstrates how to create a client for a network service.
|
||||
|
||||
This example uses QTcpSocket, and is intended to be run alongside the
|
||||
\l{fortuneserver}{Fortune Server} example or
|
||||
the \l{threadedfortuneserver}{Threaded Fortune Server} example.
|
||||
|
||||
\image fortuneclient-example.png Screenshot of the Fortune Client example
|
||||
|
||||
This example uses a simple QDataStream-based data transfer protocol to
|
||||
request a line of text from a fortune server (from the
|
||||
\l{fortuneserver}{Fortune Server} example). The client requests a
|
||||
fortune by simply connecting to the server. The server then responds with
|
||||
a QString which contains the fortune text.
|
||||
|
||||
QTcpSocket supports two general approaches to network programming:
|
||||
|
||||
\list
|
||||
|
||||
\li \e{The asynchronous (non-blocking) approach.} Operations are scheduled
|
||||
and performed when control returns to Qt's event loop. When the operation
|
||||
is finished, QTcpSocket emits a signal. For example,
|
||||
QTcpSocket::connectToHost() returns immediately, and when the connection
|
||||
has been established, QTcpSocket emits
|
||||
\l{QTcpSocket::connected()}{connected()}.
|
||||
|
||||
\li \e{The synchronous (blocking) approach.} In non-GUI and multithreaded
|
||||
applications, you can call the \c waitFor...() functions (e.g.,
|
||||
QTcpSocket::waitForConnected()) to suspend the calling thread until the
|
||||
operation has completed, instead of connecting to signals.
|
||||
|
||||
\endlist
|
||||
|
||||
In this example, we will demonstrate the asynchronous approach. The
|
||||
\l{blockingfortuneclient}{Blocking Fortune Client} example
|
||||
illustrates the synchronous approach.
|
||||
|
||||
Our class contains some data and a few private slots:
|
||||
|
||||
\snippet fortuneclient/client.h 0
|
||||
|
||||
Other than the widgets that make up the GUI, the data members include a
|
||||
QTcpSocket pointer, a QDataStream object that operates on the socket, and
|
||||
a copy of the fortune text currently displayed.
|
||||
|
||||
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:
|
||||
|
||||
\snippet fortuneclient/client.cpp 0
|
||||
\dots
|
||||
\snippet fortuneclient/client.cpp 1
|
||||
|
||||
The protocol is based on QDataStream, so we set the stream device to the
|
||||
newly created socket. 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.
|
||||
|
||||
The only QTcpSocket signals we need in this example are
|
||||
QTcpSocket::readyRead(), signifying that data has been received, and
|
||||
QTcpSocket::errorOccurred(), which we will use to catch any connection errors:
|
||||
|
||||
\dots
|
||||
\snippet fortuneclient/client.cpp 3
|
||||
\dots
|
||||
\snippet fortuneclient/client.cpp 5
|
||||
|
||||
Clicking the \uicontrol{Get Fortune} button will invoke the \c
|
||||
requestNewFortune() slot:
|
||||
|
||||
\snippet fortuneclient/client.cpp 6
|
||||
|
||||
Because we allow the user to click \uicontrol{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 \l{QTcpSocket::connectToHost()}{connectToHost()},
|
||||
one of two things can happen:
|
||||
|
||||
\list
|
||||
\li \e{The connection is established.} In this case, the server will send us a
|
||||
fortune. QTcpSocket will emit \l{QTcpSocket::readyRead()}{readyRead()}
|
||||
every time it receives a block of data.
|
||||
|
||||
\li \e{An error occurs.} We need to inform the user if the connection
|
||||
failed or was broken. In this case, QTcpSocket will emit
|
||||
\l{QTcpSocket::errorOccurred()}{errorOccurred()}, and \c Client::displayError() will be
|
||||
called.
|
||||
\endlist
|
||||
|
||||
Let's go through the \l{QTcpSocket::errorOccurred()}{errorOccurred()} case first:
|
||||
|
||||
\snippet fortuneclient/client.cpp 13
|
||||
|
||||
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 \l{QTcpSocket::readyRead()}{readyRead()} alternative. This
|
||||
signal is connected to \c Client::readFortune():
|
||||
|
||||
\snippet fortuneclient/client.cpp 8
|
||||
|
||||
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 \l{QTcpSocket::readyRead()}{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.
|
||||
|
||||
For this purpose we use a QDataStream read transaction. It keeps reading
|
||||
stream data into an internal buffer and rolls it back in case of an
|
||||
incomplete read. We start by calling startTransaction() which also resets
|
||||
the stream status to indicate that new data was received on the socket.
|
||||
We proceed by using QDataStream's streaming operator to read the fortune
|
||||
from the socket into a QString. Once read, we complete the transaction by
|
||||
calling QDataStream::commitTransaction(). If we did not receive a full
|
||||
packet, this function restores the stream data to the initial position,
|
||||
after which we can wait for a new readyRead() signal.
|
||||
|
||||
After a successful read transaction, we call QLabel::setText() to display
|
||||
the fortune.
|
||||
|
||||
\sa {Fortune Server}, {Blocking Fortune Client}
|
||||
*/
|
75
examples/network/doc/src/fortuneserver.qdoc
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example fortuneserver
|
||||
\title Fortune Server
|
||||
\examplecategory {Networking}
|
||||
\meta tags {tcp,network,server}
|
||||
\ingroup examples-network
|
||||
\brief Demonstrates how to create a server for a network service.
|
||||
|
||||
This example is intended to be run alongside the
|
||||
\l{fortuneclient}{Fortune Client} example or the
|
||||
\l{blockingfortuneclient}{Blocking Fortune Client} example.
|
||||
|
||||
\image fortuneserver-example.png Screenshot of the Fortune Server example
|
||||
|
||||
It uses QTcpServer to accept incoming TCP connections, and a
|
||||
simple QDataStream based data transfer protocol to write a fortune to the
|
||||
connecting client (from the \l{fortuneclient}{Fortune Client}
|
||||
example), before closing the connection.
|
||||
|
||||
\snippet fortuneserver/server.h 0
|
||||
|
||||
The server is implemented using a simple class with only one slot, for
|
||||
handling incoming connections.
|
||||
|
||||
\snippet fortuneserver/server.cpp 1
|
||||
|
||||
In its constructor, our Server object calls QTcpServer::listen() to set up
|
||||
a QTcpServer to listen on all addresses, on an arbitrary port. In then
|
||||
displays the port QTcpServer picked in a label, so that user knows which
|
||||
port the fortune client should connect to.
|
||||
|
||||
\snippet fortuneserver/server.cpp 2
|
||||
|
||||
Our server generates a list of random fortunes that it can send to
|
||||
connecting clients.
|
||||
|
||||
\snippet fortuneserver/server.cpp 3
|
||||
|
||||
When a client connects to our server, QTcpServer will emit
|
||||
QTcpServer::newConnection(). In turn, this will invoke our
|
||||
sendFortune() slot:
|
||||
|
||||
\snippet fortuneserver/server.cpp 4
|
||||
|
||||
The purpose of this slot is to select a random line from our list of
|
||||
fortunes, encode it into a QByteArray using QDataStream, and then write it
|
||||
to the connecting socket. This is a common way to transfer binary data
|
||||
using QTcpSocket. First we create a QByteArray and a QDataStream object,
|
||||
passing the bytearray to QDataStream's constructor. We then explicitly set
|
||||
the protocol version of QDataStream to QDataStream::Qt_5_10 to ensure that
|
||||
we can communicate with clients from future versions of Qt (see
|
||||
QDataStream::setVersion()). We continue by streaming in a random fortune.
|
||||
|
||||
\snippet fortuneserver/server.cpp 7
|
||||
|
||||
We then call QTcpServer::nextPendingConnection(), which returns the
|
||||
QTcpSocket representing the server side of the connection. By connecting
|
||||
QTcpSocket::disconnected() to QObject::deleteLater(), we ensure that the
|
||||
socket will be deleted after disconnecting.
|
||||
|
||||
\snippet fortuneserver/server.cpp 8
|
||||
|
||||
The encoded fortune is written using QTcpSocket::write(), and we finally
|
||||
call QTcpSocket::disconnectFromHost(), which will close the connection
|
||||
after QTcpSocket has finished writing the fortune to the network. Because
|
||||
QTcpSocket works asynchronously, the data will be written after this
|
||||
function returns, and control goes back to Qt's event loop. The socket
|
||||
will then close, which in turn will cause QObject::deleteLater() to delete
|
||||
it.
|
||||
|
||||
\sa {Fortune Client}, {Threaded Fortune Server}
|
||||
*/
|
81
examples/network/doc/src/http.qdoc
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example http
|
||||
\examplecategory {Networking}
|
||||
\meta tags {http,network,https,proxy}
|
||||
\title HTTP Client
|
||||
\ingroup examples-network
|
||||
\brief Demonstrates a simple HTTP client.
|
||||
|
||||
This example demonstrates how a simple HTTP client can fetch files
|
||||
from remote hosts.
|
||||
|
||||
\image http-example.webp
|
||||
|
||||
The main work of this example is done in the HttpWindow class.
|
||||
Thus we will focus on that.
|
||||
|
||||
\snippet http/httpwindow.cpp qnam-download
|
||||
|
||||
Using QNetworkAccessManager, we begin the download of a resource as
|
||||
pointed to by the \c url. If you are unfamiliar with it or the function used,
|
||||
QNetworkAccessManager::get(), or simply want to look into it in more detail,
|
||||
take a look at its documentation and the documentation for
|
||||
QNetworkReply and QNetworkRequest.
|
||||
|
||||
\snippet http/httpwindow.cpp connecting-reply-to-slots
|
||||
|
||||
Above, we connect some of the reply's signals to slots in the class.
|
||||
These slots will take care of both incoming data and finalizing the
|
||||
download/handling errors.
|
||||
|
||||
\snippet http/httpwindow.cpp networkreply-readyread-1
|
||||
|
||||
As for handling the incoming data, since we don't know the maximum
|
||||
download size of any potential input and we don't want to exhaust
|
||||
the memory of any computer which might run the example program, we
|
||||
handle incoming data in QNetworkReply::readyRead() instead of in
|
||||
QNetworkReply::finished().
|
||||
|
||||
\snippet http/httpwindow.cpp networkreply-readyread-2
|
||||
|
||||
Then we write the data to file as it arrives. It is less convenient,
|
||||
but the application will consume less memory at its peak!
|
||||
|
||||
\snippet http/httpwindow.cpp sslerrors-1
|
||||
|
||||
With the QNetworkReply::sslErrors() signal we can also handle errors that may
|
||||
occur during the TLS handshake when connecting to secure websites (i.e. HTTPS).
|
||||
|
||||
\snippet http/httpwindow.cpp sslerrors-2
|
||||
|
||||
In this example, we show a dialog to the user so that they can choose whether
|
||||
or not to ignore the errors.
|
||||
|
||||
\snippet http/httpwindow.cpp networkreply-error-handling-1
|
||||
\snippet http/httpwindow.cpp networkreply-error-handling-2
|
||||
|
||||
If an error occurs then QNetworkReply will emit the
|
||||
QNetworkReply::errorOccurred() signal, followed by the
|
||||
QNetworkReply::finished() signal. In this example, we only connect to the
|
||||
latter. We handle any potential error(s) in the respective slot by deleting
|
||||
the file we were writing to, and display the error with our status label.
|
||||
|
||||
\snippet http/httpwindow.cpp qnam-auth-required-1
|
||||
|
||||
If you connect to a website that uses
|
||||
\l{https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication}{HTTP authentication},
|
||||
assuming you didn't supply the credentials that should be used ahead of time,
|
||||
you can handle missing credentials when the website requests it. With QNetworkAccessManager,
|
||||
we do this in a slot connected to the signal
|
||||
QNetworkAccessManager::authenticationRequired(). We make this connection once,
|
||||
in the constructor.
|
||||
|
||||
\snippet http/httpwindow.cpp qnam-auth-required-2
|
||||
|
||||
In this example, we show a dialog where the user can either insert a
|
||||
username and password, or cancel. Canceling causes the request to fail.
|
||||
|
||||
*/
|
14
examples/network/doc/src/multicastreceiver.qdoc
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example multicastreceiver
|
||||
\title Multicast Receiver
|
||||
\examplecategory {Networking}
|
||||
\meta tags {network,multicast,ipv6,ipv4,udp}
|
||||
\ingroup examples-network
|
||||
\brief Demonstrates how to receive information sent to a multicast group.
|
||||
|
||||
This example demonstrates how to receive messages sent to a multicast group.
|
||||
\image multicastreceiver-example.webp
|
||||
*/
|
16
examples/network/doc/src/multicastsender.qdoc
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example multicastsender
|
||||
\title Multicast Sender
|
||||
\examplecategory {Networking}
|
||||
\meta tags {network,multicast,ipv6,ipv4,udp}
|
||||
\ingroup examples-network
|
||||
\brief Demonstrates how to send messages to a multicast group.
|
||||
|
||||
This example demonstrates how to send messages to the clients of a
|
||||
multicast group.
|
||||
|
||||
\image multicastsender-example.webp
|
||||
*/
|
14
examples/network/doc/src/network-chat.qdoc
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example network-chat
|
||||
\title Network Chat Example
|
||||
\ingroup examples-network
|
||||
\brief Demonstrates a stateful peer-to-peer Chat client.
|
||||
|
||||
This example uses broadcasting with QUdpSocket and QNetworkInterface to
|
||||
discover its peers.
|
||||
|
||||
\image network-chat-example.png
|
||||
*/
|
16
examples/network/doc/src/securesocketclient.qdoc
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example securesocketclient
|
||||
\title Secure Socket Client Example
|
||||
\ingroup examples-network
|
||||
\brief Demonstrates how to communicate over an encrypted (SSL) connection.
|
||||
|
||||
This example uses QSslSocket to demonstrate how to communicate over an
|
||||
encrypted connection, deal with authenticity problems, and display security
|
||||
and certificate information.
|
||||
|
||||
\image securesocketclient.png
|
||||
\image securesocketclient2.png
|
||||
*/
|
100
examples/network/doc/src/secureudpclient.qdoc
Normal file
@ -0,0 +1,100 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example secureudpclient
|
||||
\title DTLS client
|
||||
\ingroup examples-network
|
||||
\brief This example demonstrates how to implement client-side DTLS connections.
|
||||
|
||||
\image secureudpclient-example.png Screenshot of the DTLS client example.
|
||||
|
||||
\note The DTLS client example is intended to be run alongside the \l{secureudpserver}{DTLS server} example.
|
||||
|
||||
The example DTLS client can establish several DTLS connections to one
|
||||
or many DTLS servers. A client-side DTLS connection is implemented by the
|
||||
DtlsAssociation class. This class uses QUdpSocket to read and write datagrams
|
||||
and QDtls for encryption:
|
||||
|
||||
\snippet secureudpclient/association.h 0
|
||||
|
||||
The constructor sets the minimal TLS configuration for the new DTLS connection,
|
||||
and sets the address and the port of the server:
|
||||
|
||||
\dots
|
||||
\snippet secureudpclient/association.cpp 1
|
||||
\dots
|
||||
|
||||
The QDtls::handshakeTimeout() signal is connected to the handleTimeout() slot
|
||||
to deal with packet loss and retransmission during the handshake phase:
|
||||
|
||||
\dots
|
||||
\snippet secureudpclient/association.cpp 2
|
||||
\dots
|
||||
|
||||
To ensure we receive only the datagrams from the server, we connect our UDP socket to the server:
|
||||
|
||||
\dots
|
||||
\snippet secureudpclient/association.cpp 3
|
||||
\dots
|
||||
|
||||
The QUdpSocket::readyRead() signal is connected to the readyRead() slot:
|
||||
|
||||
\dots
|
||||
\snippet secureudpclient/association.cpp 13
|
||||
\dots
|
||||
|
||||
When a secure connection to a server is established, a DtlsAssociation object
|
||||
will be sending short ping messages to the server, using a timer:
|
||||
|
||||
\snippet secureudpclient/association.cpp 4
|
||||
|
||||
startHandshake() starts a handshake with the server:
|
||||
|
||||
\snippet secureudpclient/association.cpp 5
|
||||
|
||||
The readyRead() slot reads a datagram sent by the server:
|
||||
|
||||
\snippet secureudpclient/association.cpp 6
|
||||
|
||||
If the handshake was already completed, this datagram is decrypted:
|
||||
|
||||
\snippet secureudpclient/association.cpp 7
|
||||
|
||||
otherwise, we try to continue the handshake:
|
||||
|
||||
\snippet secureudpclient/association.cpp 8
|
||||
|
||||
When the handshake has completed, we send our first ping message:
|
||||
|
||||
\snippet secureudpclient/association.cpp 9
|
||||
|
||||
The pskRequired() slot provides the Pre-Shared Key (PSK) needed during the handshake
|
||||
phase:
|
||||
|
||||
\snippet secureudpclient/association.cpp 14
|
||||
|
||||
\note For the sake of brevity, the definition of pskRequired() is oversimplified.
|
||||
The documentation for the QSslPreSharedKeyAuthenticator class explains in detail
|
||||
how this slot can be properly implemented.
|
||||
|
||||
pingTimeout() sends an encrypted message to the server:
|
||||
|
||||
\snippet secureudpclient/association.cpp 10
|
||||
|
||||
During the handshake phase the client must handle possible timeouts, which
|
||||
can happen due to packet loss. The handshakeTimeout() slot retransmits
|
||||
the handshake messages:
|
||||
|
||||
\snippet secureudpclient/association.cpp 11
|
||||
|
||||
Before a client connection is destroyed, its DTLS connection must be shut down:
|
||||
|
||||
\snippet secureudpclient/association.cpp 12
|
||||
|
||||
Error messages, informational messages, and decrypted responses from servers
|
||||
are displayed by the UI:
|
||||
|
||||
\snippet secureudpclient/mainwindow.cpp 0
|
||||
*/
|
||||
|
107
examples/network/doc/src/secureudpserver.qdoc
Normal file
@ -0,0 +1,107 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example secureudpserver
|
||||
\title DTLS server
|
||||
\ingroup examples-network
|
||||
\brief This examples demonstrates how to implement a simple DTLS server.
|
||||
|
||||
\image secureudpserver-example.png Screenshot of the DTLS server example.
|
||||
|
||||
\note The DTLS server example is intended to be run alongside the \l{secureudpclient}{DTLS client} example.
|
||||
|
||||
The server is implemented by the DtlsServer class. It uses QUdpSocket,
|
||||
QDtlsClientVerifier, and QDtls to test each client's reachability, complete a handshake,
|
||||
and read and write encrypted messages.
|
||||
|
||||
\snippet secureudpserver/server.h 0
|
||||
|
||||
The constructor connects the QUdpSocket::readyRead() signal to its
|
||||
readyRead() slot and sets the minimal needed TLS configuration:
|
||||
|
||||
\snippet secureudpserver/server.cpp 1
|
||||
|
||||
\note The server is not using a certificate and is relying on Pre-Shared
|
||||
Key (PSK) handshake.
|
||||
|
||||
listen() binds QUdpSocket:
|
||||
|
||||
\snippet secureudpserver/server.cpp 2
|
||||
|
||||
The readyRead() slot processes incoming datagrams:
|
||||
|
||||
\dots
|
||||
\snippet secureudpserver/server.cpp 3
|
||||
\dots
|
||||
|
||||
After extracting an address and a port number, the server first tests
|
||||
if it's a datagram from an already known peer:
|
||||
|
||||
\dots
|
||||
\snippet secureudpserver/server.cpp 4
|
||||
\dots
|
||||
|
||||
If it is a new, unknown address and port, the datagram is processed as a
|
||||
potential ClientHello message, sent by a DTLS client:
|
||||
|
||||
\dots
|
||||
\snippet secureudpserver/server.cpp 5
|
||||
\dots
|
||||
|
||||
If it's a known DTLS client, the server either decrypts the datagram:
|
||||
|
||||
\dots
|
||||
\snippet secureudpserver/server.cpp 6
|
||||
\dots
|
||||
|
||||
or continues a handshake with this peer:
|
||||
|
||||
\dots
|
||||
\snippet secureudpserver/server.cpp 7
|
||||
\dots
|
||||
|
||||
handleNewConnection() verifies it's a reachable DTLS client, or sends a
|
||||
HelloVerifyRequest:
|
||||
|
||||
\snippet secureudpserver/server.cpp 8
|
||||
\dots
|
||||
|
||||
If the new client was verified to be a reachable DTLS client, the server creates
|
||||
and configures a new QDtls object, and starts a server-side handshake:
|
||||
|
||||
\dots
|
||||
\snippet secureudpserver/server.cpp 9
|
||||
\dots
|
||||
|
||||
doHandshake() progresses through the handshake phase:
|
||||
|
||||
\snippet secureudpserver/server.cpp 11
|
||||
|
||||
During the handshake phase, the QDtls::pskRequired() signal is emitted and
|
||||
the pskRequired() slot provides the preshared key:
|
||||
|
||||
\snippet secureudpserver/server.cpp 13
|
||||
|
||||
\note For the sake of brevity, the definition of pskRequired() is oversimplified.
|
||||
The documentation for the QSslPreSharedKeyAuthenticator class explains in detail
|
||||
how this slot can be properly implemented.
|
||||
|
||||
After the handshake is completed for the network peer, an encrypted DTLS
|
||||
connection is considered to be established and the server decrypts subsequent
|
||||
datagrams, sent by the peer, by calling decryptDatagram(). The server also
|
||||
sends an encrypted response to the peer:
|
||||
|
||||
\snippet secureudpserver/server.cpp 12
|
||||
|
||||
The server closes its DTLS connections by calling QDtls::shutdown():
|
||||
|
||||
\snippet secureudpserver/server.cpp 14
|
||||
|
||||
During its operation, the server reports errors, informational messages, and
|
||||
decrypted datagrams, by emitting signals errorMessage(), warningMessage(),
|
||||
infoMessage(), and datagramReceived(). These messages are logged by the server's
|
||||
UI:
|
||||
|
||||
\snippet secureudpserver/mainwindow.cpp 0
|
||||
*/
|
85
examples/network/doc/src/threadedfortuneserver.qdoc
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example threadedfortuneserver
|
||||
\title Threaded Fortune Server
|
||||
\examplecategory {Networking}
|
||||
\meta tags {tcp,network,threading,server,synchronous-io}
|
||||
\ingroup examples-network
|
||||
|
||||
\brief The Threaded Fortune Server example shows how to create a server for a
|
||||
simple network service that uses threads to handle requests from different
|
||||
clients. It is intended to be run alongside the Fortune Client example.
|
||||
|
||||
\image threadedfortuneserver-example.png
|
||||
|
||||
The implementation of this example is similar to that of the
|
||||
\l{fortuneserver}{Fortune Server} example, but here we will
|
||||
implement a subclass of QTcpServer that starts each connection in a
|
||||
different thread.
|
||||
|
||||
For this we need two classes: FortuneServer, a QTcpServer subclass, and
|
||||
FortuneThread, which inherits QThread.
|
||||
|
||||
\snippet threadedfortuneserver/fortuneserver.h 0
|
||||
|
||||
FortuneServer inherits QTcpServer and reimplements
|
||||
QTcpServer::incomingConnection(). We also use it for storing the list of
|
||||
random fortunes.
|
||||
|
||||
\snippet threadedfortuneserver/fortuneserver.cpp 0
|
||||
|
||||
We use FortuneServer's constructor to simply generate the list of
|
||||
fortunes.
|
||||
|
||||
\snippet threadedfortuneserver/fortuneserver.cpp 1
|
||||
|
||||
Our implementation of QTcpServer::incomingConnection() creates a
|
||||
FortuneThread object, passing the incoming socket descriptor and a random
|
||||
fortune to FortuneThread's constructor. By connecting FortuneThread's
|
||||
finished() signal to QObject::deleteLater(), we ensure that the thread
|
||||
gets deleted once it has finished. We can then call QThread::start(),
|
||||
which starts the thread.
|
||||
|
||||
\snippet threadedfortuneserver/fortunethread.h 0
|
||||
|
||||
Moving on to the FortuneThread class, this is a QThread subclass whose job
|
||||
is to write the fortune to the connected socket. The class reimplements
|
||||
QThread::run(), and it has a signal for reporting errors.
|
||||
|
||||
\snippet threadedfortuneserver/fortunethread.cpp 0
|
||||
|
||||
FortuneThread's constructor simply stores the socket descriptor and
|
||||
fortune text, so that they are available for run() later on.
|
||||
|
||||
\snippet threadedfortuneserver/fortunethread.cpp 1
|
||||
|
||||
The first thing our run() function does is to create a QTcpSocket object
|
||||
on the stack. What's worth noticing is that we are creating this object
|
||||
inside the thread, which automatically associates the socket to the
|
||||
thread's event loop. This ensures that Qt will not try to deliver events
|
||||
to our socket from the main thread while we are accessing it from
|
||||
FortuneThread::run().
|
||||
|
||||
\snippet threadedfortuneserver/fortunethread.cpp 2
|
||||
|
||||
The socket is initialized by calling QTcpSocket::setSocketDescriptor(),
|
||||
passing our socket descriptor as an argument. We expect this to succeed,
|
||||
but just to be sure, (although unlikely, the system may run out of
|
||||
resources,) we catch the return value and report any error.
|
||||
|
||||
\snippet threadedfortuneserver/fortunethread.cpp 3
|
||||
|
||||
As with the \l{fortuneserver}{Fortune Server} example, we encode
|
||||
the fortune into a QByteArray using QDataStream.
|
||||
|
||||
\snippet threadedfortuneserver/fortunethread.cpp 4
|
||||
|
||||
But unlike the previous example, we finish off by calling
|
||||
QTcpSocket::waitForDisconnected(), which blocks the calling thread until
|
||||
the socket has disconnected. Because we are running in a separate thread,
|
||||
the GUI will remain responsive.
|
||||
|
||||
\sa {Fortune Server}, {Fortune Client}, {Blocking Fortune Client}
|
||||
*/
|
14
examples/network/doc/src/torrent.qdoc
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example torrent
|
||||
\title Torrent Example
|
||||
\ingroup examples-network
|
||||
\brief Demonstrates complex TCP/IP operations.
|
||||
|
||||
This example demonstrates some of the complex TCP/IP operations
|
||||
supported by the Qt Network APIs.
|
||||
|
||||
\image torrent-example.png
|
||||
*/
|