Hello dear fellow programmers,
we try to write an application that will run on windows phone and android.
Part of this app ist to establish a secure connection to a websocket server, which does not work on the windows phone. Works however perfect under Linux.
//constructor opening connection
MeteorDDP::MeteorDDP(QString uri){
QUrl wsUri = QUrl("wss://"+uri+"/websocket");
qDebug()<<wsUri;
connect(&wsClient, &QWebSocket::textMessageReceived,this, &MeteorDDP::handleMessage);
connect(&wsClient, &QWebSocket::connected,this, &MeteorDDP::onConnected);
connect(&wsClient, &QWebSocket::stateChanged, this, &MeteorDDP::onStateChanged);
connect(&wsClient, static_cast<void(QWebSocket::*)(QAbstractSocket::SocketError)>(&QWebSocket::error),
[=](QAbstractSocket::SocketError error){
qDebug()<<error<<"error";
});
connect(&wsClient, &QWebSocket::sslErrors, this, &MeteorDDP::onSslError);
wsClient.open(wsUri);
wsClient.flush();
}
And a method which just should output connected:
void MeteorDDP::onConnected(){
qDebug()<<"connected";
}
H file:
#ifndef METEORDDP_H
#define METEORDDP_H
#include <QString>
#include <QHash>
#include <QUrl>
#include <QtWebSockets/QtWebSockets>
class MeteorDDP : public QObject
{
Q_OBJECT
public:
MeteorDDP(QString server);
protected:
QWebSocket wsClient;
void onConnected();
void onStateChanged(QAbstractSocket::SocketState state);
void onSslError(void);
void onError(QAbstractSocket::SocketError error);
}
Methods:
void MeteorDDP::onStateChanged(QAbstractSocket::SocketState state){
qDebug() <<state<<"state Changed";
}
void MeteorDDP::onError(QAbstractSocket::SocketError error){
qDebug()<<error <<"error";
}
void MeteorDDP::onSslError(){
qDebug() <<"ssl error";
}
Related
See EDIT1 at the end of the question for a possible solution - It would be great if somebody could comment on my interpretation, so that I can understand better what's happening
I'm writing a simple TCP client, based on QTcpSocket and managed by a QStateMachine (connect to server -> transmit data -> if disconnected for any reason, reconnect to server).
I noticed that if the connection is shut down on the server side (client is notified with RemoteHostClosedError), after reconnection the QTcpSocket write() method succeeds but no data is transmitted on the wire - nothing is received by the server, and the bytesWritten() signal on the client side does not fire up.
I found in the documentation for error() signal (https://doc.qt.io/qt-5/qabstractsocket.html#error) that
When this signal is emitted, the socket may not be ready for a reconnect attempt. In that case,
attempts to reconnect should be done from the event loop".
I think I'm already ok with that, as the reconnection happens in one of the QStateMachine states, and QStateMachine should have its own event loop according to the QT docs.
Below some simplified code to reproduce the issue (sorry, not so minimal but I could not find a simpler way to show the problem):
testclient.h
#ifndef TESTCLIENT_H
#define TESTCLIENT_H
#include <QObject>
#include <QTcpSocket>
#include <QDebug>
#include <QStateMachine>
class TestClient : public QObject
{
Q_OBJECT
public:
explicit TestClient(QObject *parent = nullptr);
public slots:
void start();
signals:
// FSM events
void fsmEvtConnected();
void fsmEvtError();
private slots:
void onSocketConnected(); // Notify connection to TCP server
void onSocketDisconnected(); // Notify disconnection from TCP server
void onSocketBytesWritten(qint64 bytes); // Notify number of bytes written to TCP server
void onSocketError(QAbstractSocket::SocketError err);
// FSM state enter/exit actions
void onfsmConnectEntered();
void onfsmTransmitEntered();
void onfsmTransmitExited();
private:
// Member variables
QTcpSocket* m_socket; // TCP socket used for communications to server
QStateMachine* m_clientFsm; // FSM defining general client behaviour
private:
void createClientFsm(); // Create client FSM
};
#endif // TESTCLIENT_H
testclient.cpp
#include "testclient.h"
#include <QState>
#include <QThread> // Sleep
//-----------------------------------------------------------------------------
// PUBLIC METHODS
//-----------------------------------------------------------------------------
TestClient::TestClient(QObject *parent) : QObject(parent)
{
m_socket = new QTcpSocket(this);
connect(m_socket, SIGNAL(connected()),this, SLOT(onSocketConnected()));
connect(m_socket, SIGNAL(disconnected()),this, SLOT(onSocketDisconnected()));
connect(m_socket, SIGNAL(bytesWritten(qint64)),this, SLOT(onSocketBytesWritten(qint64)));
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError)));
}
void TestClient::start()
{
createClientFsm();
m_clientFsm->start();
}
//-----------------------------------------------------------------------------
// TCP CONNECTION MANAGEMENT SLOTS
//-----------------------------------------------------------------------------
void TestClient::onSocketConnected()
{
qDebug() << "connected...";
emit fsmEvtConnected();
}
void TestClient::onSocketDisconnected()
{
qDebug() << "disconnected...";
emit fsmEvtError();
}
void TestClient::onSocketBytesWritten(qint64 bytes)
{
qDebug() << bytes << " bytes written...";
}
void TestClient::onSocketError(QAbstractSocket::SocketError err)
{
qDebug() << "socket error " << err;
}
//-----------------------------------------------------------------------------
// FSM MANAGEMENT
//-----------------------------------------------------------------------------
void TestClient::createClientFsm()
{
m_clientFsm = new QStateMachine(this);
// Create states
QState* sConnect = new QState();
QState* sTransmit = new QState();
// Add transitions between states
sConnect->addTransition(this, SIGNAL(fsmEvtConnected()), sTransmit);
sTransmit->addTransition(this, SIGNAL(fsmEvtError()), sConnect);
// Add entry actions to states
connect(sConnect, SIGNAL(entered()), this, SLOT(onfsmConnectEntered()));
connect(sTransmit, SIGNAL(entered()), this, SLOT(onfsmTransmitEntered()));
// Add exit actions to states
connect(sTransmit, SIGNAL(exited()), this, SLOT(onfsmTransmitExited()));
// Create state machine
m_clientFsm->addState(sConnect);
m_clientFsm->addState(sTransmit);
m_clientFsm->setInitialState(sConnect);
}
void TestClient::onfsmConnectEntered()
{
qDebug() << "connecting...";
m_socket->connectToHost("localhost", 11000);
// Wait for connection result
if(!m_socket->waitForConnected(10000))
{
qDebug() << "Error: " << m_socket->errorString();
emit fsmEvtError();
}
}
void TestClient::onfsmTransmitEntered()
{
qDebug() << "sending data...";
m_socket->write("TEST MESSAGE");
}
void TestClient::onfsmTransmitExited()
{
qDebug() << "waiting before reconnection attempt...";
QThread::sleep(2);
}
main.cpp
#include <QCoreApplication>
#include "testclient.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
TestClient client(&a);
client.start();
return a.exec();
}
To test, you can just launch netcat (nc -l -p 11000) , then close the nc process after receiving TEST MESSAGE and finally relaunch it again. The second time, TEST MESSAGE is not received, and we don't have the onSocketBytesWritten() printout, see below:
connecting...
connected...
sending data...
12 bytes written... <<<<<<<<<< Correct transmission, event fires up
socket error QAbstractSocket::RemoteHostClosedError
disconnected...
waiting before reconnection attempt...
connecting...
connected...
sending data... <<<<<<<<<< No transmission, event does not fire up, no socket errors!
EDIT1: I found out that if I create the QTcpSocket on connection and destroy it on disconnection, the problem does not happen. Is this the expected/proper way to use sockets?
Wouldn't it be possible instead to create the socket just once and just connect/disconnect? Maybe it is just a matter of flushing or cleaning up in a specific manner, but I could not find it so far.
Here are the modifications that make the code above work on server-side disconnection:
Move socket creation from class constructor to onfsmConnectEntered() - handler for entry in the "Connect" QState:
void TestClient::onfsmConnectEntered()
{
m_socket = new QTcpSocket(this);
connect(m_socket, SIGNAL(connected()),this, SLOT(onSocketConnected()));
connect(m_socket, SIGNAL(disconnected()),this, SLOT(onSocketDisconnected()));
connect(m_socket, SIGNAL(bytesWritten(qint64)),this, SLOT(onSocketBytesWritten(qint64)));
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError)));
qDebug() << "connecting...";
m_socket->connectToHost("localhost", 11000);
// The rest of the method is the same
}
Delete the socket on disconnection, so that it is deallocated and will be created again on reconnection:
void TestClient::onSocketDisconnected()
{
qDebug() << "disconnected...";
m_socket->deleteLater();
m_socket = nullptr;
emit fsmEvtError();
}
Do not use waitForX methods as they block the event loop and prevent them from using that resource as the signals do not do their job correctly or the QStateMachine.
Considering the above, the solution is:
void TestClient::onfsmConnectEntered()
{
m_socket->connectToHost("localhost", 11000);
}
But even so your code has errors since it does not consider other cases such as:
If when you start the client the server is not running, your application will try to connect the error will be launched and nothing else.
If the server fails for a longer time than the 10000 ms timeout set to waitForConnected(), the same will happen as in the previous case.
Then the idea is to try to connect until you are sure of the connection and that can be done through a QTimer with an appropriate period.
testclient.h
#ifndef TESTCLIENT_H
#define TESTCLIENT_H
#include <QObject>
class QTcpSocket;
class QStateMachine;
class QTimer;
#include <QAbstractSocket>
class TestClient : public QObject
{
Q_OBJECT
public:
explicit TestClient(QObject *parent = nullptr);
public slots:
void start();
signals:
// FSM events
void fsmEvtConnected();
void fsmEvtError();
private slots:
void onSocketConnected(); // Notify connection to TCP server
void onSocketDisconnected(); // Notify disconnection from TCP server
void onSocketBytesWritten(qint64 bytes); // Notify number of bytes written to TCP server
void onSocketError(QAbstractSocket::SocketError err);
// FSM state enter/exit actions
void onfsmConnectEntered();
void onfsmTransmitEntered();
private:
// Member variables
QTcpSocket* m_socket; // TCP socket used for communications to server
QStateMachine* m_clientFsm; // FSM defining general client behaviour
QTimer* m_timer;
private:
void createClientFsm(); // Create client FSM
void tryConnect();
};
#endif // TESTCLIENT_H
testclient.cpp
#include "testclient.h"
#include <QState>
#include <QStateMachine>
#include <QTcpSocket>
#include <QThread> // Sleep
#include <QTimer>
//-----------------------------------------------------------------------------
// PUBLIC METHODS
//-----------------------------------------------------------------------------
TestClient::TestClient(QObject *parent) : QObject(parent)
{
m_socket = new QTcpSocket(this);
m_timer = new QTimer(this);
m_timer->setInterval(100);
connect(m_timer, &QTimer::timeout, this, &TestClient::tryConnect);
connect(m_socket, &QAbstractSocket::connected,this, &TestClient::onSocketConnected);
connect(m_socket, &QAbstractSocket::disconnected,this, &TestClient::onSocketDisconnected);
connect(m_socket, &QIODevice::bytesWritten,this, &TestClient::onSocketBytesWritten);
connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), this, &TestClient::onSocketError);
}
void TestClient::start()
{
createClientFsm();
m_clientFsm->start();
}
//-----------------------------------------------------------------------------
// TCP CONNECTION MANAGEMENT SLOTS
//-----------------------------------------------------------------------------
void TestClient::onSocketConnected()
{
m_timer->stop();
qDebug() << "connected...";
emit fsmEvtConnected();
}
void TestClient::onSocketDisconnected()
{
qDebug() << "disconnected...";
emit fsmEvtError();
}
void TestClient::onSocketBytesWritten(qint64 bytes)
{
qDebug() << bytes << " bytes written...";
}
void TestClient::onSocketError(QAbstractSocket::SocketError err)
{
qDebug() << "socket error " << err;
}
//-----------------------------------------------------------------------------
// FSM MANAGEMENT
//-----------------------------------------------------------------------------
void TestClient::createClientFsm()
{
m_clientFsm = new QStateMachine(this);
// Create states
QState* sConnect = new QState();
QState* sTransmit = new QState();
// Add transitions between states
sConnect->addTransition(this, SIGNAL(fsmEvtConnected()), sTransmit);
sTransmit->addTransition(this, SIGNAL(fsmEvtError()), sConnect);
// Add entry actions to states
connect(sConnect, &QAbstractState::entered, this, &TestClient::onfsmConnectEntered);
connect(sTransmit, &QAbstractState::entered, this, &TestClient::onfsmTransmitEntered);
// Create state machine
m_clientFsm->addState(sConnect);
m_clientFsm->addState(sTransmit);
m_clientFsm->setInitialState(sConnect);
}
void TestClient::tryConnect(){
m_socket->connectToHost("localhost", 11000);
}
void TestClient::onfsmConnectEntered()
{
m_timer->start();
}
void TestClient::onfsmTransmitEntered()
{
qDebug() << "sending data...";
m_socket->write("TEST MESSAGE");
}
I am making a multiple game. I need to take command from client. This means I have GUI and TcpServer. So I need to work them simultaneously. I used Thread but it doesnt work. Could you please help me to find the problem?
Summarizing: Firstly player press the "online" button. Then Oyun() Gui function runs and button connected with connectPressed() function. In this function there is a thread in order to run read the client commands when Gui is working.
Firstly I used QTimer in order to take command from Client in every 1 second. But My GUI freezed. And Then I used QThread but according to my research, QThread is not proper for GUI app. So I found Qtconcurrent, QFutureWatcher and QFuture. But my thread is still not working. I should have made a mistake somewhere.
#include <QApplication>
#include <anaclass.h>
#include <player2.h>
#include <tcpserver.h>
#include <QThread>
#include <QObject>
//#include <worker.h>
AnaClass *anaclass;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
anaclass = new AnaClass();
anaclass->show();
anaclass->Giris(); //button selection page
return a.exec();
}
#include "anaclass.h"
Puan *puanlama1;
Puan *puanlama2;
player2 *yilan2;
AnaClass::AnaClass() : QGraphicsView()
{
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
setFixedSize(800,600);
scene = new QGraphicsScene;
scene->setSceneRect(0,0,800,600);
setScene(scene);
}
void AnaClass::Giris()
{
connectButton = new Button("Online");
double cxPos = this->width()/2 - connectButton->boundingRect().width()/2;
double cyPos= 425;
connectButton->setPos(cxPos, cyPos);
connect(connectButton, SIGNAL(clicked()), this, SLOT(connectPressed()));
scene->addItem(connectButton);
}
void AnaClass::Oyun()
{
scene->clear();
puanlama1 = new Puan();
puanlama1->setDefaultTextColor(Qt::blue);
puanlama1->setPos(5, 2);
scene->addItem(puanlama1);
yilan = new Yilan();
yilan->setRect(0,0,19,19);
scene->addItem(yilan);
yilan->setFlags(QGraphicsItem::ItemIsFocusable);
yilan->setFocus();
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(Qt::blue);
yilan->setBrush(brush);
if(stringButtonName == "Player2" || stringButtonName == "Online")
{
yilan->setPos(scene->width()/2 + 60, scene->height()/2);
}
else
{
yilan->setPos(scene->width()/2, scene->height()/2);
}
if(stringButtonName == "Player2" || stringButtonName == "Online")
{
yilan->playerNumber=1;
puanlama2 = new Puan();
puanlama2->setDefaultTextColor(Qt::green);
puanlama2->setPos(700, 2);
scene->addItem(puanlama2);
yilan2 = new player2();
yilan2->setRect(0,0,19,19);
scene->addItem(yilan2);
yilan2->setFlags(QGraphicsItem::ItemIsFocusable);
yilan2->setFocus();
QBrush brush2;
brush2.setStyle(Qt::SolidPattern);
brush2.setColor(Qt::green);
yilan2->setBrush(brush2);
yilan2->setPos(scene->width()/2 - 60,scene->height()/2);
}
emit emitTcp();
}
void AnaClass::connectPressed()
{
qDebug()<<"connect basildi";
server = new TCPServer();
server->Test();
stringButtonName = connectButton->buttonName;
qDebug()<<"Gelen Veri " + server->OkunanBilgi;
QFutureWatcher<void> watcher;
connect(&watcher, SIGNAL(finished()), server, SLOT(daimaOku()), Qt::QueuedConnection);
QFuture<void> deneme = QtConcurrent::run(this, &AnaClass::emitTcp);
watcher.setFuture(deneme);
Oyun();
}
}
#ifndef ANACLASS_H
#define ANACLASS_H
#include <QGraphicsScene>
#include <QGraphicsView>
#include <yilan.h>
#include <Meyve.h>
#include <QBrush>
#include <Puan.h>
#include <player2.h>
#include <QThread>
#include <label.h>
#include <QKeyEvent>
#include <button.h>
#include <QDebug>
#include <tcpserver.h>
#include <QTime>
#include <QTimer>
#include <QMutex>
//#include <worker.h>
#include <QFuture>
#include <QtConcurrent>
#include <QFutureWatcher>
class AnaClass : public QGraphicsView
{
Q_OBJECT
public:
AnaClass();
void Giris();
void Oyun();
void timerEvent(QTimerEvent *event);
void keyPressEvent(QKeyEvent *event2);
public:
Yilan *yilan;
//QThread *thread;
QGraphicsScene *scene;
Label *label1;
Button* player1Button;
Button* player2Button;
Button* connectButton;
TCPServer *server;
QTimer *timerOnline;
public:
int k=0;
int t=0;
QString stringButtonName;
signals:
void emitTcp();
public slots:
void connectPressed();
void player1Pressed();
void player2Pressed();
};
#endif // ANACLASS_H
#define TCPSERVER_H
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
#include <QObject>
#include <QTimer>
class TCPServer : public QObject
{
Q_OBJECT
public:
TCPServer(QObject* parent = nullptr);
void Test();
signals:
//void emitTcp();
public slots:
void newConnection();
void daimaOku(); // always read as english
public:
QTcpServer *server;
QTcpSocket *socket;
QTimer *timerTcp;
QString OkunanBilgi;
};
#endif // TCPSERVER_H
#include "tcpserver.h"
TCPServer::TCPServer(QObject * parent) : QObject()
{
}
void TCPServer::Test()
{
server = new QTcpServer();
connect(server, SIGNAL(newConnection()), this, SLOT(newConnection()));
if(!server->listen(QHostAddress::Any, 1234))
{
qDebug()<<"server baslamadi";
}
else
{
qDebug()<<"server basladi";
}
//timerTcp = new QTimer();
//connect(timerTcp, SIGNAL(timeout()), this, SLOT(daimaOku()));
//emit emitTcp();
}
void TCPServer::newConnection()
{
qDebug()<<"newconnection";
socket = server->nextPendingConnection();
socket->write("Merhaba Client");
socket->flush();
socket->waitForBytesWritten(5000);
timerTcp->start(50);
}
void TCPServer::daimaOku() //alwaysread() as english
{
qDebug()<<"always read function is working";
// if(socket->state() == QAbstractSocket::ConnectedState)
// {
// qDebug()<<"Daima oku fonsiyonu soket bagli";
// socket->waitForReadyRead();
// OkunanBilgi = socket->readAll();
// qDebug()<<"Tcp daima oku :" + OkunanBilgi;
// }
}
Thank you for your comments. I solved the problem by deleting QFuture and adding connect() like below.
timerOnline = new QTimer();
connect(timerOnline, SIGNAL(timeout()), server, SLOT(daimaOku()));
timerOnline->start(500);
But I have another problem. When Client connects the server, my Gui app freezes. You can find the revised code below.
void TCPServer::daimaOku()
{
qDebug()<<"Function is running";
if(socket->state() == QAbstractSocket::UnconnectedState)
{
qDebug()<<"Socket is not connected";
}
else
{
qDebug()<<"Socket connected";
socket->waitForReadyRead();
OkunanBilgi = socket->readAll();
qDebug()<<"Tcp always read :" + OkunanBilgi;
}
}
When client is not connected, the output is:
Function is running
Socket is not connected
Socket is not connected ...
I can play the game but when client is connected, game freezes. I don't understand why.
I want to use IPC in order to exchange messages between two separate applications. The first one is a BASH script which is fired when a specific udev rule is activated (in Ubuntu Linux), and the other one is a simple Qt 5.7 console application, which acts as a server.
I already have the Qt server working and printing a message when it accepts a connection to the specified socket. What I'm trying to achieve now, is to make the server do something not when it accepts a connection, but when it receives a certain "message". Any ideas on how to do it?
Below is my code:
server.cpp
#include "server.h"
Server::Server() : QThread()
{
m_server = new QLocalServer(this);
m_server->listen("somesocket.sock");
connect(m_server, &QLocalServer::newConnection, this, &Server::testFunction);
}
Server::~Server()
{
m_server->removeServer("somesocket.sock");
}
void Server::run()
{
}
void Server::testFunction(){
qDebug() << "Sth happened!";
return;
}
server.h
#ifndef SERVER_H
#define SERVER_H
#include <QThread>
#include <QObject>
#include <QDebug>
#include <QLocalServer>
class Server : public QThread
{
public:
Server();
~Server();
void run();
void testFunction();
private:
QLocalServer *m_server;
signals:
void connectionEstablished(bool);
};
#endif // SERVER_H
You could connect to readyRead signal, and then check received message, like in this example:
connect( this, SIGNAL(readyRead()), SLOT(readClient()) );
void readClient()
{
QTextStream ts( this );
int line = 0;
while ( canReadLine() ) {
QString str = ts.readLine();
if(str == "someSpecialMessage")
{
//...
}
line++;
}
}
for more informations about this signal, see documentation: http://doc.qt.io/qt-5/qiodevice.html#readyRead
This is also an example of client and server applications in Qt, using QSocket and QServerSocket: https://doc.qt.io/archives/3.3/clientserver-example.html
I am trying to implement a library to connect to an external resource and interact with it via an XML-based API. However I don't know how to get all the data before processing it. I am using QTcpSocket on Windows.
The way I have to interact with the resource is as follow:
Connect to the server
Send an XML message with credentials
Get the response from the server
Parse the XML response to extract the session ID
Send other requests in XML with the session ID in it and parse the XML responses.
Use the result in my application
Of course, depending on the request the message will not have the same structure so I need to parse the XML in the same function, right? And if so, how can I wait for all the data to arrive before parsing it?
Furthermore, as mentioned, it is under a Windows environment so I cannot use "waitForReadyRead" since as stated in the documentation:
This function may fail randomly on Windows. Consider using the event loop and the readyRead() signal if your software will run on Windows.
How does it work?
Thanks,
Fred
Edit
Here is my current code:
Client.cpp
#include "client.h"
#include <pugixml.hpp>
#include <map>
#include <sstream>
#include <string>
#include "task.h" // Generate the API message, not relevant
Client::Client(const QString& server, const QString& port, QObject* parent):
QObject(parent)
{
connectToServer(server, port);
connect(&socket_, &QTcpSocket::readyRead, this, &Client::getResult);
}
void Client::connectToServer(const QString& server, const QString& port)
{
bool ok;
int portNumber = port.toInt(&ok);
if (ok) {
if (socket_.state() == QTcpSocket::SocketState::ConnectedState)
socket_.disconnectFromHost();
socket_.connectToHost(server, portNumber);
} else {
throw tr("Cannot connect to server %1 on port %2. Make sure the provided information are correct.")
.arg(server)
.arg(port);
}
}
void Client::throwOnError(const pugi::xml_document& doc)
{
pugi::xpath_node_set errors = doc.select_nodes("/EXECUTION/TASK/RESULTSET/RESULT/MESSAGE");
std::string error_message = "";
for (pugi::xpath_node_set::const_iterator it = errors.begin(); it != errors.end(); ++it)
{
pugi::xml_node node = it->node();
if (std::string(node.attribute("type").value()) == "Error" ||
std::string(node.attribute("type").value()) == "Warning")
error_message += node.child_value();
}
if (!error_message.empty())
throw std::exception(error_message.c_str());
}
void Client::sendMessage(const QString &message)
{
outMessage = message;
result_.clear();
socket_.write(message.toUtf8());
}
void Client::getResult()
{
emit startReading();
while (socket_.bytesAvailable() > 0) {
result_.append(socket_.readAll());
socket_.flush();
}
resultMessage = QString(result_);
emit finishedReading();
}
void Client::login(const QString& user, const QString& password, const QString& project)
{
std::map<QString, QString> whereFields {{"userName", user}, {"password", password}};
QString request = prepareMessage("Login", "Security", std::map<QString, QString>(), whereFields); // Generates the XML message for the API
sendMessage(request);
// Wait for data to arrive - How ?
std::stringstream xmlResult = getXmlData(result_); // Remove the header from the API response and convert the QByteArray to a std::stringstream
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load(xmlResult);
throwOnError(doc);
pugi::xpath_node session = doc.select_node("/EXECUTION/TASK/RESULTSET/DATASETS/DATASET/secId");
sessionId_ = QString::fromStdString(session.node().first_child().value());
projectName_ = project;
emit taskCompleted();
}
Client.h
#ifndef Client_H
#define Client_H
#include <QObject>
#include <QTcpSocket>
#include <QByteArray>
#include <map>
#include <set>
#include "pugixml.hpp"
class Client : public QObject
{
Q_OBJECT
public:
Client(QObject* parent = 0) : QObject(parent) {}
Client(const QString& server, const QString& port, QObject* parent = 0);
// Connection
void connectToServer(const QString& server, const QString& port);
void login(const QString& user, const QString& password, const QString& project);
void logout();
QString const getSessionId() { return sessionId_; }
void throwOnError(const pugi::xml_document& doc);
QString sessionId() const { return sessionId_; }
QString outMessage; // For testing
QString resultMessage; // For testing
signals:
void ready();
void startReading();
void finishedReading();
void taskCompleted();
private slots:
void getResult();
private:
void sendMessage(const QString& message);
QTcpSocket socket_;
QString sessionId_;
QString projectName_;
QByteArray result_;
};
#endif // Client_H
i have simple request method inside simple http client , that QRunnble worker is invoking
all the returners of the request are status 0 ,
what more i spotted after few tests is, when i give the app to run with 1 thread that is
only 1 url to process its working fine and i get status 200 .
i suspect something in my http client code is worng and does not support multi thread mode
here is my full httpclient code:
this is the code of the request :
#ifndef _HttpClient_
#define _HttpClient_
#include <QNetworkAccessManager>
#include <QtNetwork>
#include <QUrl>
QT_BEGIN_NAMESPACE
class QSslError;
class QAuthenticator;
class QNetworkReply;
QT_END_NAMESPACE
class HttpClient : public QObject
{
Q_OBJECT
public:
HttpClient(QFile* file,QMutex* mutex);
~HttpClient();
void startRequest(QString& url);
public slots:
#ifndef QT_NO_OPENSSL
void sslErrors(QNetworkReply*,const QList<QSslError> &errors);
#endif
private:
QString m_sUrl;
QUrl m_url;
QNetworkAccessManager* m_networkManager;
QNetworkReply *reply;
int httpGetId;
void HandleNetworkError(QNetworkReply::NetworkError& networkError,
QNetworkReply *networkReply);
};
#endif
------------------------------------
#include "HttpClient.h"
#include <QMutexLocker>
#include <QTextStream>
HttpClient::HttpClient()
{
m_networkManager = new QNetworkAccessManager(this);
}
HttpClient::~HttpClient()
{
;
}
void HttpClient::startRequest(QString& url)
{
QNetworkRequest request;
request.setUrl(QUrl(url));
QEventLoop loop;
reply = m_networkManager->get(request);
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
LOG_MSG("Is UrlAlive?:"+url.toStdString())
QString ApiResponse;
QByteArray data=reply->readAll();
ApiResponse.append(QString::fromUtf8(data));
int iStatusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (reply->error()) {
QNetworkReply::NetworkError networkError = reply->error();
HandleNetworkError(networkError,reply);
}
QString s = QString::number(iStatusCodeV);
reply->deleteLater();
reply = 0;
}
void HttpClient::HandleNetworkError(QNetworkReply::NetworkError& networkError,QNetworkReply *networkReply)
{
if(networkError != QNetworkReply::NoError)
{
QString err = networkReply->errorString();
LOG_MSG("HttpClient::HandleNetworkError:"+err.toStdString());
}
}
#ifndef QT_NO_OPENSSL
void HttpClient::sslErrors(QNetworkReply*,const QList<QSslError> &errors)
{
reply->ignoreSslErrors();
}
#endif
all of this called from QRunnble method that looks like this :
void ThreadWorker::run()
{
QMutexLocker lock(_m);
startwork();
lock.unlock();
}
void ThreadWorker::startwork()
{
m_pHttpClient = new HttpClient();
//each thread gets unique url
m_pHttpClient->startRequest(m_url);
}
why its failing all the time?