QNetworkReply finished signal slot not emitting on Windows 10 - qt

I have the following code to get the response of the url using QNetworkAccessManager and using QNetworkReply for getting the response code. I am getting the onReplyfinished()slot properly while testing this in windows 8. I am not getting the onReplyfinished() while using the application in Windows 10.
NetManager.h :
class NetManager:public QNetworkAccessManager
{
Q_OBJECT
public:
NetManager(QObject* inParent = 0);
~NetManager();
public slots:
void onReplyfinished();
private:
QNetworkAccessManager *AManager;
QNetworkReply *NReply;
QString urlStr;
};
NetManager.cpp :
NetManager::NetManager( QObject* inParent ) : QNetworkAccessManager(
inParent )
{
AManager = new QNetworkAccessManager(this);
urlStr= "https://sampleurl.com/";
qDebug() << urlStr;
QUrl url(urlStr);
QNetworkRequest NetRequest((url));
NReply= AManager->get(NetRequest);
connect(NReply, SIGNAL(finished()), this, SLOT(onReplyfinished()));
}
void NetManager::onReplyfinished()
{
qDebug () << "in getting response";
}
Thanks in advance

do not forget to add
QT += network in .pro file
and also if you are receiving ssl problems do not forget to copy libcryptoand libsslinto your project directory

Related

QProcess does not emit finished signal

I try to read out the output of a command executed in QProcess. I don't get the connection working between QProcess's finished signal and a finished handler.
I tried several different ways of connecting to QProcess finished signal but no luck so far. I know that the process executes because it prints the output in the GUI's console and that the process finishes because it passes the waitForFinished method from sequential API.
Why does my code not hit onFinish or onFinishNoPams?
header:
class Test : public QObject
{
Q_OBJECT
public:
Test(QObject *parent = 0);
Q_INVOKABLE void read();
public slots:
void onFinish(int exitCode , QProcess::ExitStatus exitStatus);
void onFinishNoPams();
private:
QProcess *m_process;
};
cpp:
Test::Test(QObject *parent)
: QObject(parent)
{}
void Test::read(){
m_process=new QProcess(this);
connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinishNoPams()));
connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinish(int,QProcess::ExitStatus)));
connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
[=](int exitCode, QProcess::ExitStatus exitStatus){
qDebug() << "not reached";
});
connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this,&Test::onFinish);
QString program = "lsusb";
QStringList arguments;
m_process->execute(program,arguments);
m_process->waitForFinished();
qDebug() << "reached";
return;
}
void Test::onFinish(int exitCode , QProcess::ExitStatus exitStatus){
qDebug() << "not reached";
}
void Test::onFinishNoPams(){
qDebug() << "not reached";
QByteArray out=m_process->readAllStandardOutput();
}
qml:
import test 1.0
Window {
Test{
id:test
Component.onCompleted: test.read()
}
}
QProcess::execute() is a static method that starts the external process and waits for its completion in a blocking way. It has nothing to do with your m_process variable. What you want to use is QProcess::start().

How to deal with HTTP 301 status code?

I am creating a small program that will pull information from a website in order to learn. Specifically, I am trying to pull the archived winning numbers from this lotto website.
https://www.ohiolottery.com/WinningNumbers/KenoDrawings/KenoDrawingsArchive.aspx?date=01%2f01%2f2010
Here is the code I currently have (with QT += network in the pro file):
Retriever.h
#ifndef RETRIEVER_H
#define RETRIEVER_H
#include <QObject>
#include <QtNetwork>
#include <QDebug>
class Retriever : public QObject
{
Q_OBJECT
public:
explicit Retriever(QObject *parent = 0);
void fetch();
public slots:
void replyFinished(QNetworkReply* reply);
private:
QNetworkAccessManager* manager;
};
#endif // RETRIEVER_H
Retriever.cpp
#include "retriever.h"
Retriever::Retriever(QObject *parent) : QObject(parent)
{
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
}
void Retriever::fetch()
{
QString stackoverflow = "http://stackoverflow.com";
QString lotto = "https://www.ohiolottery.com/WinningNumbers/KenoDrawings/KenoDrawingsArchive.aspx?date=01%2f01%2f2010";
manager->get(QNetworkRequest(QUrl(lotto)));
}
void Retriever::replyFinished(QNetworkReply *reply)
{
if (reply->error() == QNetworkReply::NoError) qDebug() << "no error";
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug() << reply->url();
qDebug() << reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
qDebug() << statusCode;
if (reply->atEnd()) qDebug() << "already at end";
while (!reply->atEnd()) {
QByteArray data = reply->readLine();
QString::fromUtf8(data.data(), data.size());
QString str(data);
qDebug() << str;
}
}
When I run this with stackoverflow, it works fine. But when I run this with the lotto website, I get the following output from qDebug:
no error
QUrl("https://www.ohiolottery.com/WinningNumbers/KenoDrawings/KenoDrawingsArchive.aspx?date=01%2F01%2F2010")
QUrl("/mobile")
301
already at end
There seems to be a few issues. First, there is no error but it thinks its a mobile site? Then it thinks its already at the end of the content (I'm assuming that its because of 301 status code). I'm not familiar with retrieving information from websites, so I'm not sure how to deal with this error. I copied the url exactly from the website, so I don't know why its redirecting. How can I resolve this error? More specifically, how can I get the correct URL to give to the QNetworkAccessManager?
Status 301 tells you have to fetch data from another url which in your case is /mobile.
You need to set user-agent request header to a web browser, because that website thinks you are a mobile client.
QNetworkRequest request(QUrl(lotto));
request.setHeader(QNetworkRequest::UserAgentHeader, QVariant("Mozilla/5.0 "));
manager->get(request);

QT QTcpServer::incomingConnection(qintptr handle) not firing?

I'm trying to create a multithreaded server using Qt for the first time. Normally one would use the socket pointer returned by the QTcpServer::nextPendingConnection() with the socket handle already baked in - but since I'm interfacing with the connecting client on a separate thread, I need to create the socket separately using the qintptr handle from QTcpServer::incomingConnection(qintptr handle). After a very dreary, error-packed debugging session I managed to track down the problem to the QTcpServer::incomingConnection() never being fired?
Has anyone had a similar problem - has something changed over recent versions Qt?
These are the ones I've tried:
QTcpServer::incomingConnection(qintptr handle)
QTcpServer::incomingConnection(qintptr socketDescriptor)
QTcpServer::incomingConnection(int handle)
EDIT:
Creating instance of server:
TestServer *myServer = new TestServer();
myServer->initializeServer(1234);
Which calls:
void TestServer::initializeServer(quint16 port)
{
mainServer = new QTcpServer(this);
mainServer->listen(QHostAddress::Any, port);
qDebug() << "Listening for connections on port: " << port;
}
Server is now listening. When a client connects incomingConnection(qintptr handle) is supposed to be called:
void TestServer::incomingConnection(qintptr socketDescriptor){
TestClient *client = new TestClient(this);
client->setSocket(socketDescriptor);
}
Which calls:
void TestClient::setSocket(quint16 socketDescr)
{
socket = new QTcpSocket(this);
socket->setSocketDescriptor(socketDescr);
connect(socket, SIGNAL(connected()),this,SLOT(connected()));
connect(socket, SIGNAL(disconnected()),this,SLOT(disconnected()));
connect(socket, SIGNAL(readyRead()),this,SLOT(readyRead()));
}
Called on connect() signal:
void TestClient::connected()
{
qDebug() << "Client connected..."; // This debug never appears in the console, since QTcpServer::incomingConnection isn't being fired.
}
You have some errors at your code:
At TestServer your QTcpServer probably aggregated, but you need to inherit it. At this case you try to override incomingConnection() method, but you haven't base class and you just create new incomingConnection(), not override.
You get qintptr descriptor variable from incomingConnection(), but set quint16 type at setSocket() method.
You probably mix client of server and client of your part, which just get incoming connection and handling socket data.
I write some little example below for your understanding tcp client-server communication.
Server part
Main part is server themselves:
#include <QTcpServer>
class TestServer: public QTcpServer
{
public:
TestServer(QObject *parent = 0);
void incomingConnection(qintptr handle) Q_DECL_OVERRIDE;
};
Just look: I don't aggragate QTcpServer, but inherited it. At this case you can override incomingConnection() method correctly.
At constructor we just start server for listening using listen() method:
TestServer::TestServer(QObject *parent):
QTcpServer(parent)
{
if (this->listen(QHostAddress::Any, 2323)) {
qDebug() << "Server start at port: " << this->serverPort();
} else {
qDebug() << "Start failure";
}
}
Then time for overriding incomingConnection():
void TestServer::incomingConnection(qintptr handle)
{
qDebug() << Q_FUNC_INFO << " new connection";
SocketThread *socket = new SocketThread(handle);
connect(socket, SIGNAL(finished()), socket, SLOT(deleteLater()));
socket->start();
}
I create SocketThread object which handle incoming data:
#include <QThread>
#include <QObject>
class QTcpSocket;
class SocketThread: public QThread
{
Q_OBJECT
public:
SocketThread(qintptr descriptor, QObject *parent = 0);
~SocketThread();
protected:
void run() Q_DECL_OVERRIDE;
private slots:
void onConnected();
void onReadyRead();
void onDisconnected();
private:
QTcpSocket *m_socket;
qintptr m_descriptor;
};
We inherits from QThread for making our server multithreading, so we have to override run() method:
SocketThread::SocketThread(qintptr descriptor, QObject *parent)
: QThread(parent), m_descriptor(descriptor)
{
}
void SocketThread::run()
{
qDebug() << Q_FUNC_INFO;
m_socket = new QTcpSocket;
m_socket->setSocketDescriptor(m_descriptor);
connect(m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()), Qt::DirectConnection);
connect(m_socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()), Qt::DirectConnection);
exec();
}
This way we initialize our QTcpSocket, set socket descriptor, connect it with readyRead() and disconnected() signals and start event loop.
void SocketThread::onReadyRead()
{
QDataStream in(m_socket);
in.setVersion(QDataStream::Qt_5_5);
QString message;
in >> message;
qDebug() << message;
m_socket->disconnectFromHost();
}
void SocketThread::onDisconnected()
{
m_socket->close();
// Exit event loop
quit();
}
At onReadyRead() just read some QString from client, write it to console and disconnect from host. At onDisconnected() we close socket connection and exit event loop.
Client part
It is just example and bad-smells style, but i create connection to the server at MainWindow class on QPushButton::clicked signal:
void MainWindow::on_pushButton_clicked()
{
QTcpSocket *client = new QTcpSocket;
connect(client, SIGNAL(connected()), this, SLOT(connected()));
connect(client, SIGNAL(disconnected()), client, SLOT(deleteLater()));
client->connectToHost(QHostAddress::LocalHost, 2323);
client->waitForConnected();
if (client->state() != QAbstractSocket::ConnectedState ) {
qDebug() << Q_FUNC_INFO << " can't connect to host";
delete client;
return;
}
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_5);
out << QString("Hello");
out.device()->seek(0);
client->write(block);
}
void MainWindow::connected()
{
qDebug() << Q_FUNC_INFO << " client connected";
}
I create new QTcpSocket, connect it to the signals and try to connect to the host(in my case it is localhost). Wait for connected and check socket status. If all is right I write to socket QString - just example.
It is one of possible ways to organized multithreading client-server architecture, i hope it will be helpfull for you and you find yours bugs.

QNetworkAccessManager does not return any data

I have come across bug that I am not able to see myself. After studing QT and stack sites I wrote following code:
void RateOfExchangeGetter::run(){
mRunning = true;
mAccessManager = new QNetworkAccessManager();
//connect(mAccessManager, SIGNAL(finished(QNetworkReply*)),
// this, SLOT(replyFinished(QNetworkReply*)));
while(mRunning){
QNetworkReply *reply;
for(SiteParser *parser: mSiteParsers){
QNetworkRequest request(QUrl("https://www.google.pl/"));
request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
qDebug() << "here";
reply = mAccessManager->get(request);
parser->setQNetworkReply(reply);
connect(reply, SIGNAL(readyRead()), parser, SLOT(slotReadyRead()));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
parser, SLOT(slotError(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
parser, SLOT(slotSslErrors(QList<QSslError>)));
}
//for test only ->
this->sleep(10);
QByteArray array = reply->read(50);
qDebug() << array;
}
}
As good eye might have already noticed - this code is placed in class that inherits QThread.
For some reason (that I cannot find) I can't receive any data from get function (I know that it is asynchronous), no signals are transmitted, and also after waiting 10 second there are no data available in read. I had also tried to get data via finished signal from QNetworkAccessManager itself but also nothing appeared.
Thanks to anyone who might have a clue what is happening.
You don't have an event loop in your thread's run() method, so there's no chance of any networking code working.
You should put all of your code into a QObject, and move it to a generic thread. The default implementation of QThread::run() spins an event loop.
I also don't see much reason for there to be more than one parser. You can simply let the QNetworkReply accumulate the response in its internal buffer until the request is finished - you can then parse it all in one go, obviating the need for parser state. Use the finished slot instead of readyRead. The readyRead slot only makes sense for large requests.
Below is how it might be done. Note the arming mechanism to prevent races between the worker thread and the main thread. You're guaranteed that the finishedAllRequests signal will be emitted exactly once after a call to arm(). Without this mechanism, the worker thread might be able to process all requests before the connect has a chance to run, and no signal will reach the recipient, or you might get multiple signals as the requests are processed before the next one is added.
#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QPointer>
#include <QSslError>
#include <QThread>
#include <QMetaMethod>
#include <QDebug>
class Parser : public QObject {
Q_OBJECT
bool m_armed;
QList<QNetworkReply*> m_replies;
QPointer<QNetworkAccessManager> m_manager;
QMetaMethod m_addRequestImpl, m_armImpl;
Q_SLOT void finished() {
QNetworkReply * reply = static_cast<QNetworkReply*>(sender());
Q_ASSERT(m_replies.contains(reply));
qDebug() << "reply" << reply << "is finished";
// ... use the data
m_replies.removeAll(reply);
if (m_armed && m_replies.isEmpty()) {
emit finishedAllRequests();
m_armed = false;
}
}
Q_SLOT void error(QNetworkReply::NetworkError) {
QNetworkReply * reply = static_cast<QNetworkReply*>(sender());
m_replies.removeAll(reply);
}
Q_SLOT void sslErrors(QList<QSslError>) {
QNetworkReply * reply = static_cast<QNetworkReply*>(sender());
m_replies.removeAll(reply);
}
Q_INVOKABLE void addRequestImpl(const QNetworkRequest & req) {
QNetworkReply * reply = m_manager->get(req);
connect(reply, SIGNAL(finished()), SLOT(finished()));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
SLOT(error(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
SLOT(sslErrors(QList<QSslError>)));
m_replies << reply;
}
Q_INVOKABLE void armImpl() {
if (m_replies.isEmpty()) {
emit finishedAllRequests();
m_armed = false;
} else
m_armed = true;
}
static QMetaMethod method(const char * signature) {
return staticMetaObject.method(staticMetaObject.indexOfMethod(signature));
}
public:
// The API is fully thread-safe. The methods can be accessed from any thread.
explicit Parser(QNetworkAccessManager * nam, QObject * parent = 0) :
QObject(parent), m_armed(false), m_manager(nam),
m_addRequestImpl(method("addRequestImpl(QNetworkRequest)")),
m_armImpl(method("armImpl()"))
{}
void addRequest(const QNetworkRequest & req) {
m_addRequestImpl.invoke(this, Q_ARG(QNetworkRequest, req));
}
void arm() {
m_armImpl.invoke(this);
}
Q_SIGNAL void finishedAllRequests();
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QThread * thread = new QThread(&a);
thread->start();
QNetworkAccessManager mgr;
Parser parser(&mgr);
mgr.moveToThread(thread);
parser.moveToThread(thread);
for (int i = 0; i < 10; ++i) {
QNetworkRequest request(QUrl("https://www.google.pl/"));
request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
parser.addRequest(request);
}
thread->connect(&parser, SIGNAL(finishedAllRequests()), SLOT(quit()));
a.connect(thread, SIGNAL(finished()), SLOT(quit()));
parser.arm();
int rc = a.exec();
thread->wait();
delete thread; // Otherwise mgr's destruction would fail
return rc;
}
#include "main.moc"
Output:
reply QNetworkReplyHttpImpl(0x1011619e0) is finished
reply QNetworkReplyHttpImpl(0x101102260) is finished
reply QNetworkReplyHttpImpl(0x101041670) is finished
reply QNetworkReplyHttpImpl(0x1011023e0) is finished
reply QNetworkReplyHttpImpl(0x10102fa00) is finished
reply QNetworkReplyHttpImpl(0x101040090) is finished
reply QNetworkReplyHttpImpl(0x101163110) is finished
reply QNetworkReplyHttpImpl(0x10103af10) is finished
reply QNetworkReplyHttpImpl(0x10103e6b0) is finished
reply QNetworkReplyHttpImpl(0x101104c80) is finished

Microsoft translator API Qt

I have a problem geting application token for Microsoft translator with QNetworkAccessManager. This is my code:
QUrl serverUrl("https://datamarket.accesscontrol.windows.net/v2/OAuth2-13");
QNetworkRequest request(serverUrl);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QUrl postData;
postData.addQueryItem("grant_type", "client_credentials");
postData.addQueryItem("client_id", ClientID);
postData.addQueryItem("client_secret", ClientSecret);
postData.addQueryItem("scope", "http://api.microsofttranslator.com");
networkAccessManager->post(request, postData.encodedQuery());
and when a finished(QNetworkReply*) signal is emitted I found that server reply contains no data at all, it is just empty! Does anyone know the solution of this problem?
UPD I checked a reply for errors and got the following: "Error creating ssl context". So I added SSL libs to my project, but got next error - "Unknown error". Any ideas?
I have used this class subclassed from QNetworkAccessManager to ignore SSL errors:
sslqnetworkaccessmanager.h
#ifndef SSLQNETWORKACCESSMANAGER_H
#define SSLQNETWORKACCESSMANAGER_H
#include <QtNetwork>
#include <QtCore>
class SslQNetworkAccessManager : public QNetworkAccessManager
{
Q_OBJECT
public:
explicit SslQNetworkAccessManager(QObject *parent = 0);
protected:
QNetworkReply* createRequest(Operation op, const QNetworkRequest & request, QIODevice * outgoingData = 0);
};
#endif // SSLQNETWORKACCESSMANAGER_H
sslqnetworkaccessmanager.cpp
#include "sslqnetworkaccessmanager.h"
SslQNetworkAccessManager::SslQNetworkAccessManager(QObject *parent)
: QNetworkAccessManager(parent)
{
}
QNetworkReply* SslQNetworkAccessManager::createRequest(Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
{
QNetworkRequest req(request);
QNetworkReply* reply = QNetworkAccessManager::createRequest(op, req, outgoingData);
reply->ignoreSslErrors();
return reply;
}
This class overrides the createRequest method and ignores any SSL errors that may occur with the QNetworkReply returned.

Resources