Reusing ASIO connection, read_some exception - http

I am currently trying to figure out how to properly reuse an asio socket. I am able to successfully send out a request, and get the result. The second time I send out a request, I get an exception: read_some: End of file. The second write seems to work fine, I see the second http request going out over wireshark. I am thinking that there is left over information on the socket that is corrupting my connection in some way. Any help would be appreciated with this issue. Here is the code I am using:
persistent_connection::persistent_connection(std::string ip, std::string port):
io_service_(), socket_(io_service_), is_setup_(false)
{
boost::asio::ip::tcp::resolver resolver(io_service_);
boost::asio::ip::tcp::resolver::query query(ip,port);
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
boost::asio::ip::tcp::endpoint endpoint = *iterator;
socket_.async_connect(endpoint, boost::bind(&persistent_connection::handler_connect, this, boost::asio::placeholders::error, iterator));
io_service_.run();
}
void persistent_connection::handler_connect(const boost::system::error_code &ec, boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
{
if(ec)
{
std::cout << "Couldn't connect" << ec << std::endl;
return;
}
else
{
boost::asio::socket_base::keep_alive keep_option(true);
socket_.set_option(keep_option);
}
}
void persistent_connection::write(std::string message)
{
std::string request_stream = "GET /" + message + " HTTP/1.0\r\n";
request_stream += "HOST: 10.1.10.220";
request_stream += "Accept: */*\r\n";
request_stream += "Connection: keep-alive\r\n\r\n";
try
{
boost::asio::write(socket_, boost::asio::buffer(request_stream, request_stream.size()));
}catch(std::exception& e)
{
std::cout << "Write exception: " << e.what() << std::endl;
}
boost::array<char,8192> buf;
try
{
socket_.read_some(boost::asio::buffer(buf));
}catch(std::exception& e)
{
std::cout << "Read exception: " << e.what() << std::endl;
}
std::string response = buf.data();
std::cout << response << std::endl;
}
Edit: Added main function.
int main()
{
persistent_connection p("10.1.10.220", "80");
std::string check;
do
{
std::cin >> check;
if(check.compare("s") == 0)
{
std::cout << "Sending" << std::endl;
p.write("100");
}
}while(check.compare("x") != 0);
}

The fact you get this exception when trying to read_some means that the HTTP server closes the connection after the first request is over, i.e. the server ignores "Connection: keep-alive" header (note that HTTP 1.0 servers don't necessarily support persistent connections).
However, in 1.1 version connections are persistent by default, so requesting "HTTP/1.1" should solve this issue.

Related

QNetworkAccessManager send data incomplete

I have a trouble with QNetworkAccessManager in windows. I wrote the following code to submit request ,it works on ubuntu perfectly but on windows send just 16384 bytes!! It seems request execute just once and freeze.
QString concatenated = username + ":" + pass;
QByteArray hash = concatenated.toLocal8Bit().toBase64();
QString headerData = "Basic " + hash;
QNetworkRequest request = QNetworkRequest(QUrl(baseURL));
request.setRawHeader("Authorization", headerData.toLocal8Bit());
request.setRawHeader("Content-Type", "application/json");
QNetworkReply * reply = nam->post(request,data);
connect(reply,&QNetworkReply::uploadProgress,this,&myClass::uploadProgress);
in uploadProgress method:
qDebug() << sent << " " << total;
if(total && sent){
int result = (sent*100)/total;
emit uploaded(result);
}
output:
16384 632054 // AND EVERY THINGS STOP UNTIL I GET QNetworkReply::RemoteHostClosedError ERROR CODE
After two days finally, I found why it happened! It because I emit the signal in uploadProgress directly! I changed the uploadProgress code like below and it works perfectly now!
qDebug() << sent << " " << total;
if(total && sent){
int result = (sent*100)/total;
QTimer::singleShot(5,[this,result](){
emit uploaded(result);
}
}

App crashes when I try to read QString from socket

I am trying to develop a Qt program using sockets for client and server communication. I need help with figuring out why my server crashes when the client connects and the server tries to get a QString?
I have this code on the server side:
void Client::onReadyRead() {
qDebug() << "On ready read!";
QDataStream in(mSocket);
in.setVersion(QDataStream::Qt_4_0);
for (;;) {
if(!mBlockSize) {
if (mSocket->bytesAvailable() < sizeof(quint16)) break;
in >> mBlockSize;
}
if(mSocket->bytesAvailable() < mBlockSize) break;
qDebug() << "Package was recieved!";
qDebug() << "Block size: " << mBlockSize;
if(Table::INVALID_ID == mUser.id()) {
QString authStr;
in >> authStr;
qDebug() << "Recieved account data: " << authStr;
}
mBlockSize = 0;
}
}
And on the client side:
void Client::onConnected()
{
qDebug() << "Connected!";
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
//Reserve 2 bytes
out << (quint16)0 << mEmail << "|" << mPassword;
//Back to the beginning
out.device()->seek(0);
//Write a block size
out << (quint16)(block.size() - sizeof(quint16));
mSocket->write(block);
}

Read all input from QSerialPort

I am receiving data in this shape:
Q1\n
9.70E-6\n
OK>
from an external device via QSerialPort, but with my reading routine
QString request = "Hello";
qDebug() << "TransAction started!";
QByteArray requestData = request.toLocal8Bit();
qDebug() << "Writing data: " << requestData;
serial->write(requestData);
qDebug() << "Data written";
if(serial->waitForBytesWritten(waitTimeout))
{
if(serial->waitForReadyRead(waitTimeout))
{
qDebug() << "Waiting for data!";
QByteArray responseData = serial->readAll();
while(serial->waitForReadyRead(100))
responseData += serial->readAll();
responseData.replace('\n', ' ');
QString response(responseData);
QByteArray response_arr = response.toLocal8Bit();
qDebug() << "Response is: " << response_arr.toHex();
emit this->response(response);
}
else
{
qDebug() << "Wait read response timeout";
emit this->timeout(tr("Wait read response timeout %1").arg(QTime::currentTime().toString()));
}
}
else
{
qDebug() << "Wait write request timeout!";
emit this->timeout(tr("Wait write request timeout %1").arg(QTime::currentTime().toString()));
}
I only get
Q1
as response. How can I modify my code such that I am able to read all input data?
Update:
When testing it with the serial port script described here: https://stackoverflow.com/a/7654527/2546099, everything works. Apparently the problem is that the qt-version stops reading after the first line break. This problem consists also if I add
char buffer[1000];
for(int i = 0; i < 1000; i++)
{
int tmp = serial->read(buffer, 1000);
if(tmp > 0)
qDebug() << buffer;
}
directly after the line
qDebug() << "Waiting for data!";
Then I still only get the first line (without the \n). Changing times does not change the received data.
The answer to my problem is (partly) described in this question: External vs internal declaration of QByteArray. My problem (why I did not receive any further data) was that I did not send a \x00D after the input line, thus the device just echoed my input, and was waiting for the Enter afterwards. After the input looks exactly as the first line, I misunderstood it for just getting the first line, and nothing else.

QNetworkAccessManager request fail (CA signed certificate)

I've got a CA signed certificate which I use for a webservices. In Chrome and Firefox everything work fine.
Now I want to write a QT-client for the webservice. But all what I get is "connection closed" after 30 seconds. If I request "https://gmail.com" or "https://www.dfn.de/" I get a proper result.
Here is my code.
void Request::send() {
QUrl url("my url");
qDebug() << "URL: " << url;
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::UserAgentHeader, userAgent);
QObject::connect(manager, &QNetworkAccessManager::authenticationRequired, this, &Request::provideAuthenication);
QObject::connect(manager, &QNetworkAccessManager::finished, this , &Request::replyFinished);
QObject::connect(manager, &QNetworkAccessManager::sslErrors, this , &Request::sslErrors);
qDebug() << "fire request";
manager->get(request);
}
void Request::provideAuthenication(QNetworkReply *, QAuthenticator *ator) {
qDebug() << "provideAuthenication";
ator->setUser("***");
ator->setPassword("***");
}
void Request::replyFinished(QNetworkReply *reply) {
if (reply->error() != QNetworkReply::NoError)
qDebug() << "Network Error: " << reply->errorString();
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute );
QVariant statusPhrase = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute );
qDebug() << "Result: " << statusCode.toInt() << " " << statusPhrase.toString();
qDebug() << "Data: " << reply->readAll();
}
void Request::sslErrors(QNetworkReply *, const QList<QSslError> &errors) {
foreach (const QSslError &error, errors) {
qDebug() << "SSL Error: " << error.errorString();
}
}
And that is the output. No sslError! No HTTP Error!
URL: QUrl( "my url" )
Network Error: "Connection closed"
Result: 0
Data: ""
So why hangs QT or the server? Did I miss something?!
It was a misconfiguration of openjdk7 (glassfish).
The hint of Aldaviva works on serverfault for me. https://serverfault.com/questions/389197/ssl-routinesssl23-writessl-handshake-failure
To bad that QT do not throw an ssl-error.

Qt Serial Port Errors - Data not getting read

I'm trying to read a serial port with the Qt SerialPort library. I can read the data using HyperTerminal.
In Qt I used the following code to try and do the same thing. Qt says the the port has been opened correctly, but for some reason, the bytesAvailable from the serial port is always 0.
serial.setPortName("COM20");
if (serial.open(QIODevice::ReadOnly))
qDebug() << "Opened port " << endl;
else
qDebug() << "Unable to open port" << endl;
serial.setDataBits(QSerialPort::Data8);
serial.setParity(QSerialPort::EvenParity);
serial.setBaudRate(QSerialPort::Baud115200);
qDebug() << "Is open?? " << serial.isOpen();
// Wait unit serial port data is ready
while (!serial.bytesAvailable())
{
//qDebug() << serial.bytesAvailable()<<endl;
continue;
}
QByteArray data = serial.read(100);
qDebug() << "This is the data -" << data << endl;
serial.close();
In comparison, MATLAB code with the same structure as the above code, successfully manages to read the serial port data
%Serial Port Grapher - Shurjo Banerjee
s = serial('COM20');
s.BaudRate = 460800;
s.Parity = 'even';
try
input('Ready to begin?');
catch
end
fopen(s);
fh = figure();
hold on;
t = 1;
while (s.BytesAvailable <= 0)
continue
end
a = fread(s, 1)
old_t = 1;
old_a = a;
while true
if (s.BytesAvailable > 0)
a = fread(s, 1)
figure(fh)
t = t + 1;
plot([old_t t], [old_a a]);
old_t = t;
old_a = a;
end
end
fclose(s);
1) It's bug: https://codereview.qt-project.org/#change,47729
Recomended for solution:
I changed line 161 in qserialport_win.cpp from:
return error;
to
return !error;
and now my simplified example works.
2) Also i recomended:
One step: Open port:
if (this->open(QIODevice::ReadWrite)) {
} else {
qDebug() << "\n Can't open port | " << this->errorString();
}
Two step: I recommend checking the parameter setting:
if (
this->setBaudRate(this->baudRate)
&& this->setDataBits(this->dataBits)
&& this->setParity(this->parity)
&& this->setStopBits(this->stopBits)
&& this->setFlowControl(this->flowControl)) {
qDebug() << "\n[ info ] Port settings successfully";
} else {
qDebug() << "\n[ error ] Port settings failed";
}
If all is well, then recomended for using SIGNAL ReadyRead() and your SLOT for receiving data.

Resources