Skip to content

Commit

Permalink
modify document to include qt gui exmaple.
Browse files Browse the repository at this point in the history
  • Loading branch information
hgoldfish committed May 28, 2018
1 parent ffb108b commit cea8a48
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 43 deletions.
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,56 @@ To create tcp server.
request->close();
});
}

A Qt GUI example to fetch web page.

// main.cpp
#include <QApplication>
#include <QTextBrowser>
#include "qtnetworkng/qtnetworkng.h"

using namespace qtng;

class HtmlWindow: public QTextBrowser
{
public:
HtmlWindow()
:operations(new CoroutineGroup) {
operations->spawn([this] {
qtng::Coroutine::sleep(1);
HttpSession session;
HttpResponse response = session.get("http://qtng.org/");
if(response.isOk()) {
setHtml(response.html());
} else {
setHtml("failed");
}
});
}

~HtmlWindow() {
delete operations;
}
private:
CoroutineGroup *operations;
};


int main(int argc, char **argv)
{
QApplication app(argc, argv);
HtmlWindow w;
w.show();
return startQtLoop(); // Qt GUI application start the eventloop using startQtLoop() instead of app.exec()
}

And its project file.

# fetch_web_content.pro
TEMPLATE = app
QT += widgets
SOURCES += main.cpp
include(qtnetworkng/qtnetworkng.pri)

As you can see, networking programming is done with very simple API.

Expand Down
57 changes: 57 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,63 @@ To create tcp server.
request->close();
});
}


A Qt GUI example to fetch web page.

.. code-block:: c++

// main.cpp
#include <QApplication>
#include <QTextBrowser>
#include "qtnetworkng/qtnetworkng.h"

using namespace qtng;

class HtmlWindow: public QTextBrowser
{
public:
HtmlWindow()
:operations(new CoroutineGroup)
{
operations->spawn([this] {
Coroutine::sleep(1);
HttpSession session;
HttpResponse response = session.get("http://qtng.org/");
if(response.isOk()) {
setHtml(response.html());
} else {
setHtml("failed");
}
});
}

~HtmlWindow()
{
delete operations;
}
private:
CoroutineGroup *operations;
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
HtmlWindow w;
w.show();
return startQtLoop(); // Qt GUI application start the eventloop using startQtLoop() instead of app.exec()
}
And its project file.

.. code-block:: text
# fetch_web_content.pro
TEMPLATE = app
QT += widgets
SOURCES += main.cpp
include(qtnetworkng/qtnetworkng.pri)
As you can see, networking programming is done with very straightforward API.

Expand Down
124 changes: 84 additions & 40 deletions docs/intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,49 +11,11 @@ The coroutine-based paradigm is not a new thing, Python, Go, and C# was using co

The traditional network programming use threads. `send()/recv()` is blocked, and then the Operating System switch current thread to another ready thread until data arrived. This is very straightforward, and easy for network programming. But threads use heavy resources, thousands of connections may consume many memory. More worst, threads cause data races, data currupt, even crashes.

Another choice is use callback-based paradigm. Before calling `send()/recv()`, use `select()/poll()/epoll()` to determine data arriving. Although `select()` is blocked, but many connections are handled in one thread. **Pseudocode** like this.

.. code-block:: c++
:caption: callback-based networking programming

class HandleRequest {
public:
HandleRequest() {
state = ReadingHeader;
fd->readyRead->addCallback(this::onReadyRead); // add fd to select() hub, if data arrived, call this::onReadRead;
}
void onReadyRead() {
const QByteArray &buf = fd->read(fd->bytesAvailable());
data.append(buf);
if (this->state == ReadingHeader) {
tryToReadHeader(data);
} else if (this->state == ReadingBody) {
tryToReadBody(data);
}
}
};

class SelectHub {
public:
typedef void* context;
typedef std::function<void(int,Context) Callback;
void addOnRead(int fd, Callback callback, Context context) {
fds.append(make_tuple(fd, callback, context));
}
private:
void run() {
while(true) {
fd, callback, context = select(fds);
callback(fd, context);
}
}
List<Tuple<int, Callback, Context>> fds;
};

Callback-based paradigm is considered "the new-age goto", hard to understand and read/write code. But it is widely used by C++ programmer for the popularity of boost::asio and other traditional C++ networking programming frameworks.
Another choice is use callback-based paradigm. Before calling `send()/recv()`, use `select()/poll()/epoll()` to determine data arriving. Although `select()` is blocked, but many connections are handled in one thread. Callback-based paradigm is considered "the new-age goto", hard to understand and read/write code. But it is widely used by C++ programmer for the popularity of boost::asio and other traditional C++ networking programming frameworks.

Coroutine-based paradigm is the now and feature of network programming. Coroutine is light-weight thread which has its own stack, not managed by Operating System but QtNetworkNg. Like thread-based paradigm, send()/recv() is blocked, but switch to another coroutine in the same thread unitl data arrived. Many coroutines can be created at low cost. Because there is only one thread, no locks or other synchoronization is needed. The API is straightforward like thread-based paradigm, but avoid the complexities of using threads.


Cross platforms
---------------

Expand All @@ -65,6 +27,7 @@ The coroutine is implemented using boost::context asm code, and support native p

In theory, QtNetworkNg can be ran in macos and ios. But there is nothing I can do before I having macos machine. And mips architecture would be supported.


Use QtNetworkNg in qmake projects
---------------------------------

Expand Down Expand Up @@ -158,6 +121,7 @@ Now you can build QtNetworkNg as usual C++/Qt library.
.. SOURCES += main.cpp
.. LIBS += qtnetworkng
The Coroutine
-------------

Expand Down Expand Up @@ -208,6 +172,77 @@ Killing coroutine safely is a big advanced feature of coroutine compare to threa

The ``CoroutineExit`` exception is handled by QtNetworkNg silently.


Special Considers for Qt GUI Application
----------------------------------------

A Qt GUI Application typically use Qt eventloop.

.. code-block:: c++
:caption: A typical Qt GUI Application

#include <QApplication>

int main(int argc, char **argv) {
QApplication app(argc, argv);
QWidget w;
w.show();
return app.exec();
}
The problem is the ``app.exec()``. It runs an eventloop not managed by QtNetworkNg, and blocks main coroutine forever.

To solve this problem, please use ``startQtLoop()`` instead of ``app.exec()``, which turn main coroutine to eventloop coroutine.

This is an example to get content from url.

.. code-block:: c++
:caption: A typical

#include <QApplication>
#include <QTextBrowser>
#include "qtnetworkng/qtnetworkng.h"

using namespace qtng;

class HtmlWindow: public QTextBrowser
{
public:
HtmlWindow()
:operations(new CoroutineGroup) {
operations->spawn([this] {
Coroutine::sleep(1);
loadNews();
});
}

~HtmlWindow() {
delete operations;
}

private:
void loadNews() {
HttpSession session;
HttpResponse response = session.get("http://qtng.org/");
if(response.isOk()) {
setHtml(response.html());
} else {
setHtml("failed");
}
}
private:
CoroutineGroup *operations;
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
HtmlWindow w;
w.show();
return startQtLoop();
}

The Socket and SslSocket
------------------------

Expand All @@ -219,6 +254,7 @@ The ``Socket`` class is a straightforward transliteration of the bsd socket inte

``Socket`` and ``SslSocket`` objects can be converted to ``SocketLike`` objects, which are useful for functions accept both ``Socket`` and ``SslSocket`` parameter.


Create Socket client
^^^^^^^^^^^^^^^^^^^^

Expand All @@ -245,6 +281,7 @@ The ``SslSocket`` has similar constructors which accpet an extra ``SslConfigurat
SslSocket s(socketDescriptor, config);
bool ok = s.connect(remoteHost, 443);


Create socket server
^^^^^^^^^^^^^^^^^^^^

Expand All @@ -268,6 +305,7 @@ Combine ``Socket`` and ``Coroutine``, you can create socket server in few lines
});
}


Http Client
-----------

Expand All @@ -277,6 +315,7 @@ HTTP 2.0 is planned.

Many concepts are inspired by *requests* module of Python.


Get url from HTTP server
^^^^^^^^^^^^^^^^^^^^^^^^

Expand All @@ -290,6 +329,7 @@ QtNetworkNg implement HTTP client in ``HttpSession`` class. To fetch data from o

The ``HttpSession`` accept and store cookies from data, so sessions is persisted among HTTP requests.


Send data to HTTP server
^^^^^^^^^^^^^^^^^^^^^^^^

Expand All @@ -311,6 +351,7 @@ Or send json data.
obj.insert("name", "fish");
HttpResponse resp = session.post(url, obj);


Get data from ``HttpResponse``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -340,6 +381,7 @@ As crypto library

QtNetworkNg can load OpenSSL dynamically, and provide many crypto routines.


Message Digest
^^^^^^^^^^^^^^

Expand All @@ -352,6 +394,7 @@ QtNetworkNg support most OpenSSL Message Digest.
m.update("data");
qDebug() << m.hexDigest();


Symmetrical encryption and decryption
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -382,6 +425,7 @@ QtNetworkNg can generate and manipulate RSA/DSA keys.
qDebug() << key.save();
PrivateKey clonedKey = PrivateKey::load(key.save());


Certificate and CertificateRequest
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
6 changes: 3 additions & 3 deletions src/socket_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -825,9 +825,9 @@ bool SocketPrivate::setOption(Socket::SocketOption option, const QVariant &value
if(!isValid())
return false;

if(option == Socket::BroadcastSocketOption) {
return true;
}
// if(option == Socket::BroadcastSocketOption) {
// return true;
// }

int n, level;
bool ok;
Expand Down

0 comments on commit cea8a48

Please sign in to comment.