I've got some class to interfere with HTTP-server.
Here is meaningfull code parts:
const QString someClass::BASEURL = QString("http://127.0.0.1:8000/?");
someClass::someClass():
manager(new QNetworkAccessManager(this))
{
}
QNetworkReply *someClass::run(QString request)
{
qDebug() << request;
QEventLoop loop;
QObject::connect(manager, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit()));
QNetworkReply *res = manager->get(QNetworkRequest(QUrl(BASEURL + request)));
loop.exec();
return res;
}
When I call method run(), sometimes (not every time) the are two identical GET-requests
(I looked with tcpdump). qDebug() executes 1 time.
Is there some error in my code? I can't see any possible explanation.
UPDATE:
After some tcpdump ouptut research.
After second request it sends packet with RST flag as an answer to FIN.
But I still can see no difference in TCP-streams that triggers the problem and that doesn't.
F.e. here is wireshark's output. Stream 8 went well. Stream 11 was duplicated with Stream 12.
I'm stuck with this. Maybe it's some protocol errors from server-size, I'm not sure. Or maybe it's a bug in QNetworkAccessManager.
Have you tried rewriting you code to be more asynchronous without using QEventLoop in a local scope? Your code looks good to me, but there might be some weird QT bug that you running into in the way it queues up requests for processing and using QEventLoop in the local scope. I usually use QNetworkAccessManager in the following manner to send GET and POST requests:
void someClass::run(QString request)
{
qDebug() << request;
QObject::connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(on_request_complete(QNetworkReply*)));
QNetworkReply *res = manager->get(QNetworkRequest(QUrl(BASEURL + request)));
}
void someClass::on_request_complete(QNetworkReply* response)
{
// Do stuff with your response here
}
Related
I'm working my way through boost's asio tutorial. I'm looking into their chat example. More specifically, I'm trying to split their chat client from a sender+receiver, to just a sender and just a receiver, but I'm seeing some behaviour that I can't explain.
The setup consists of:
boost::asio::io_service io_service;
tcp::resolver::iterator endpoint = resolver.resolve(...);
boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
boost::asio::async_connect(socket, endpoint, bind(handle_connect, ... ));
The sending portion effectively conisists of:
while (std::cin.getline(str))
io_service.post( do_write, str );
and
void do_write (string str)
{
boost::asio::async_write(socket, str, bind( handle_write, ... ));
}
The receive section consists of
void handle_connect(...)
{
boost::asio::async_read(socket, read_msg_, bind(handle_read, ...));
}
void handle_read(...)
{
std::cout << read_msg_;
boost::asio::async_read(socket, read_msg_, bind(handle_read, ...));
}
If I comment out the content of handle_connect to isolate the send portion, my other client (compiled using the original code) does not receive anything. If I revert, then comment out the content of handle_read, my other client only receives the first message.
Why is it necessary to call async_read() in order to be able to post() an async_write()?
The full unmodified code is linked above.
The problem here is that, your io_service is running out of work and stops processing requests even before you start sending your chat messages.
If you comment out the body of handle_connect, then the only work it had to do was to dispatch the handle_connect handler and then execute it once the connection was done.
std::size_t scheduler::run(asio::error_code& ec)
{
.....
mutex::scoped_lock lock(mutex_);
std::size_t n = 0;
for (; do_run_one(lock, this_thread, ec); lock.lock())
if (n != (std::numeric_limits<std::size_t>::max)())
++n;
return n;
}
So, you have to provide it with something in it's operation queue. This was done with handle_read_header handler in the original code as this handler would always be in the need of servicing till the client gets something from the server.
You can do what you want to do by providing work to the io_service.
asio::io_context io_context;
asio::io_context::work wrk(io_context); // make `run` run forever
tcp::resolver resolver(io_context);
tcp::resolver::results_type endpoints = resolver.resolve(argv[1], argv[2]);
chat_client c(io_context, endpoints);
asio::thread t(boost::bind(&asio::io_context::run, &io_context));
I'm downloading files from a remote server with Qt5.5 and everything works fine but I can't detect when a QNetworkReply returns an error.
In fact, I am trying to check the case if the user is downloading a file and suddenly, he loses his Internet connection (because why not :-) ). To do that, I start a download and unplug my Ethernet cable a few seconds after.
Is the signal QNetworkReply::error(QNetworkReply::NetworkError) emitted in this case? If yes, why am I not entering my slot in my code below?
void MyClass::download(QUrl url)
{
QNetworkRequest request = QNetworkRequest(url);
QNetworkReply *reply = pManager.get(request);
// finished() is called after error(), but try both
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestError(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(finished()), this, SLOT(requestFinished()));
}
void MyClass::requestError(QNetworkReply::NetworkError err)
{
qDebug() << "error";
}
void MyClass::requestFinished()
{
qDebug() << "finished";
}
I also connected the access manager like this :
connect(&pManager, SIGNAL(finished(QNetworkReply*)), SLOT(requestFinished(QNetworkReply*)));
When the Internet connection is not interrupted, I am going in the slot requestFinished(), but if there's not Internet anymore, I am not entering any slot.
Am I doing something wrong?
Ok, nevermind, I was doing it wrong. Since I want to check the internet connection, I have to check the network availability via QNetworkAccessManager, by doing this :
QNetworkConfigurationManager manager;
pManager.setConfiguration(manager.defaultConfiguration());
connect(&pManager, SIGNAL(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)), this, SLOT(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)));
And when the Internet breaks down, I will be in the corresponding slot.
This is my program. In this program I want to send request to a website (for example: http://www.adobe.com/products/muse.html)
I want to show the html code that return me in plain text box.
QUrl url("http://www.adobe.com/products/muse.html")
I want to give html code in "thisfile"
file.setFileName("thisfile.html");
if (!file.open(QIODevice::WriteOnly))
{
std::cerr << "Error: Cannot write file "
<< qPrintable(file.fileName()) << ": "
<< qPrintable(file.errorString()) << std::endl
return false;
}
http.setHost(url.host(),80);
http.post(url.toString(),"term=yyyy&loc=en_us&siteSection=products%3Amuse",&file);
This code doesn't work correctly and when I show the file give me false html code. What do I have to do?
Use http.get() instead of http.post() as POST method requires to set other Headers used by server.
QHttp::get() method is asynchronous too.
As your case is simple enough just to retrieve HTML response, you should go for HTTP GET IMHO. See difference between GET and POST method.
And if you have to use HTTP POST only, then check this.
QNetworkRequest request;
request.setUrl(QUrl("thisfile.html"));
QNetworkReply *reply = manager->post(request, "term=yyyy&loc=en_us&siteSection=products%3Amuse");
connect(reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
Look at QNetworkAccessManager at qt docs
You have to read information and save it to file at readyRead function
I am using Qt 4.6.3 and the following not-working code
QStringList userInfo;
QNetworkRequest netRequest(QUrl("http://api.stackoverflow.com/1.1/users/587532"));
QNetworkReply *netReply = netman->get(netRequest);
// from here onwards not working
netReply->waitForReadyRead(-1);
if (netReply->isFinished()==true)
{userInfo << do sth to reply;}
return userInfo;
as this function returns an empty QStringList, the app crashes. How to wait until the request has finished and then process the reply within one function
You can use event loop:
QEventLoop loop;
connect(netReply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
// here you have done.
Also you should consider adding some shorter then network timeout (20s?). I'm not sure if finished is called even if an error occured. So it is possible, that you have connect to error signal also.
First I recommend you to read the relevant documentation from the Qt Documentation Reference that you can find here: http://doc.qt.nokia.com/latest/classes.html.
Looking at your code sample it seems that you already have, along side with QNetworkRequest and QNetworkReply, a QNetworkAccessManager. What you need is to connect a slot to the finished(QNetworkReply *) signal. This signal is emitted whenever a pending network reply is finished.
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl("http://api.stackoverflow.com")));
Now, in your slot, you can read the data which was sent in response to your request. Something like:
void MyClass::MySlot(QNetworkReply *data) {
QFile file("dataFromRequest");
if (!file.open(QIODevice::WriteOnly))
return;
file.write(data->readAll());
file.close();
}
EDIT:
To wait synchronously for a signal use QEventLoop. You have an example here
http://wiki.forum.nokia.com/index.php/How_to_wait_synchronously_for_a_Signal_in_Qt
These replies here are all using old syntax and do not apply to the latest QT.
To wait for the network request to finish:
QEventLoop loop;
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();
I'm developing an application that uses IPC between a local server and a client application. There is nothing particular to it, as it's structured like the Qt documentation and examples.
The problem is that the client sends packets frequently and connecting/disconnecting from the server local socket (named pipe on NT) is very slow. So what I'm trying to achieve is a "persistent" connection between the two applications.
The client application connects to the local server (QLocalServer) without any problem:
void IRtsClientImpl::ConnectToServer(const QString& name)
{
connect(_socket, SIGNAL(connected()), this, SIGNAL(connected()));
_blockSize = 0;
_socket->abort();
_socket->connectToServer(name, QIODevice::ReadWrite);
}
And sends requests also in the traditional Qt manner:
void IRtsClientImpl::SendRequest( quint8 cmd, const QVariant* const param_array,
unsigned int cParams )
{
// Send data through socket
QByteArray hdr(PROTO_BLK_HEADER_PROJ);
QByteArray dataBlock;
QDataStream out(&dataBlock, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_5);
quint8 command = cmd;
out << blocksize_t(0) // block size
<< hdr // header
<< quint32(PROTO_VERSION_PROJ) // protocol version
<< command // command
<< cParams; // number of valid parameters
for (unsigned int i = 0; i < cParams; ++i)
out << param_array[i];
// Write the current block size
out.device()->seek(0);
out << dataBlock.size() - sizeof(blocksize_t);
_socket->write(dataBlock);
}
No problem. But the trick resides on the readyRead() signal in the server-side. Here's the current implementation of the readyRead() handling slot:
void IRtsServerImpl::onReadyRead()
{
QDataStream in(_lsock);
in.setVersion(QDataStream::Qt_4_5);
if (_blocksize == 0)
{
qDebug("Bytes Available on socket: %d", _lsock->bytesAvailable());
if (_lsock->bytesAvailable() < sizeof(blocksize_t))
return;
in >> _blocksize;
}
// We need more data?
if (_lsock->bytesAvailable() < _blocksize)
return;
ReadRequest(in);
// Reset
_blocksize = 0;
}
Without setting _blocksize to zero I could not receive more data, only the first block group (I would expect an entire block to arrive without segmentation since this is through a pipe, but it does not, go figure). I expect that behavior, sure, since the _blocksize does not represent the current stream flow anymore. All right, resetting _blocksize does the trick, but I can't resend another packet from the client without getting an increasing array of bytes on the socket. What I want is to process the request in ReadRequest and receive the next data blocks without resorting to connecting/reconnecting the applications involved.
Maybe I should 'regulate' the rate of the incoming data?
Thank you very much.