pre-connecting TCP and SSL sockets for HTTP(S) requests in Qt apps

When consuming data from a Web service, Qt applications often need to read credentials from disk (like e.g. an OAuth token) before making the network request via HTTP or HTTPS. Qt 5.2 introduces API to connect one or several sockets to a server without actually making an HTTP(S) request. This is helpful to save time e.g. at application startup: An application can first connect one or several sockets, then read credentials needed to make the HTTP request, and then make the actual HTTP request. Connecting the sockets and reading the credentials could then happen in parallel. The new API consists of one method to make a TCP handshake (including DNS lookup) and one method to make an SSL handshake (including DNS lookup and TCP handshake): void QNetworkAccessManager::connectToHost(

const QString &hostName, quint16 port = 80); void QNetworkAccessManager::connectToHostEncrypted(

const QString &hostName, quint16 port = 443,

const QSslConfiguration &sslConfiguration =

QSslConfiguration::defaultConfiguration()); For a situation where preconnecting several sockets is benefitial, consider the following. An app retrieves a JSON file from a server: QNetworkRequest request(QUrl(QStringLiteral(

"https://www.server.com/file.json"))); QNetworkReply *reply = networkAccessManager->get(request); // here connect signals etc. Suppose "file.json" looks something like this: { "images": [ { "url": "https://www.server.com/image1.jpg" }, { "url": "https://www.server.com/image2.jpg" }, { "url": "https://www.server.com/image3.jpg" }, { "url": "https://www.server.com/image4.jpg" } ], ... } The normal way would be to wait until the request to retrieve "file.json" is finished, then parse the JSON data, and issue 4 more requests to the server (note that this scenario is similar to a browser retrieving a HTML file and while parsing it, finding out it needs to retrieve more resources). Qt could re-use one open socket (the one used to retrieve "file.json", unless the server closed it), but it would have to open 3 new sockets for the other images. Assuming a network round trip of 200 milliseconds, which is typical for a Wifi connection, 3 of the 4 images would be loaded after around 1.8 seconds:

without-preconnect.png

With using the new preconnecting API, the app can start the TCP and SSL handshakes for all sockets at the same time. Thus, when the initial JSON file is retrieved, the handshakes are already done or at least in-flight, and all that is left to do is making the HTTP request: QNetworkRequest request(QUrl(

QStringLiteral("https://www.server.com/file.json"))); QNetworkReply *reply = networkAccessManager->get(request); // here connect signals etc. for (int a = 0; a < 3; ++a) { networkAccessManager->connectToHostEncrypted(

QStringLiteral("https://www.server.com")); }

with-preconnect.png

This cuts down the retrieval time of 3 of the images by more than half a second. A good idea might be to make the number of sockets to preconnect dependent on the bearer type (see QNetworkConfiguration::bearerType()): When on a WLAN network, preconnecting sockets can be done more aggressively than on e.g. a 3G or 4G network, where the user might pay per used data. When a specific number of sockets is going to be used anyhow, then preconnecting can be used unconditionally.

Featured Posts
Recent Posts
RSS Feed