doc/src/examples/blockingfortuneclient.qdoc
branchRCL_3
changeset 7 3f74d0d4af4c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/src/examples/blockingfortuneclient.qdoc	Thu Apr 08 14:19:33 2010 +0300
@@ -0,0 +1,230 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+    \example network/blockingfortuneclient
+    \title Blocking Fortune Client Example
+
+    The Blocking Fortune Client example shows how to create a client for a
+    network service using QTcpSocket's synchronous API in a non-GUI thread.
+
+    \image blockingfortuneclient-example.png
+
+    QTcpSocket supports two general approaches to network programming:
+
+    \list
+
+    \o \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()}.
+    
+    \o \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{network/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 examples/network/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 examples/network/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 examples/network/blockingfortuneclient/fortunethread.cpp 4
+    \snippet examples/network/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 examples/network/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 examples/network/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. Now it's
+    time to see what the fortune server has sent us.
+
+    \snippet examples/network/blockingfortuneclient/fortunethread.cpp 9
+    \snippet examples/network/blockingfortuneclient/fortunethread.cpp 10
+
+    This step is to read the size of the packet. Although we are only reading
+    two bytes here, and the \c while loop may seem to overdo it, we present this
+    code to demonstrate a good pattern for waiting for data using
+    QTcpSocket::waitForReadyRead(). It goes like this: For as long as we still
+    need more data, we call waitForReadyRead(). If it returns false,
+    we abort the operation. After this statement, we know that we have received
+    enough data.
+
+    \snippet examples/network/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, and read the size
+    of the packet.
+
+    \snippet examples/network/blockingfortuneclient/fortunethread.cpp 12
+    \snippet examples/network/blockingfortuneclient/fortunethread.cpp 13
+
+    Again, we'll use a loop that waits for more data by calling
+    QTcpSocket::waitForReadyRead(). In this loop, we're waiting until
+    QTcpSocket::bytesAvailable() returns the full packet size.
+
+    \snippet examples/network/blockingfortuneclient/fortunethread.cpp 14
+
+    Now that we have all the data that we need, we can use QDataStream to
+    read the fortune string from the packet. The resulting fortune is
+    delivered by emitting newFortune().
+
+    \snippet examples/network/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 closed at the call to wakeOne():
+
+    \snippet examples/network/blockingfortuneclient/fortunethread.cpp 1
+    \dots
+    \snippet examples/network/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 examples/network/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 examples/network/blockingfortuneclient/blockingclient.h 0
+
+    BlockingClient is very similar to the Client class in the
+    \l{network/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 examples/network/blockingfortuneclient/blockingclient.cpp 0
+    \snippet examples/network/blockingfortuneclient/blockingclient.cpp 1
+
+    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 examples/network/blockingfortuneclient/blockingclient.cpp 2
+
+    The requestNewFortune() slot calls FortuneThread::requestNewFortune(),
+    which \e shedules the request. When the thread has received a new fortune
+    and emits newFortune(), our showFortune() slot is called:
+
+    \snippet examples/network/blockingfortuneclient/blockingclient.cpp 3
+    \codeline
+    \snippet examples/network/blockingfortuneclient/blockingclient.cpp 4
+    
+    Here, we simply display the fortune we received as the argument.
+
+    \sa {Fortune Client Example}, {Fortune Server Example}
+*/